crypt32: Add additional path for Solaris 11 Express.
[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     This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec);
803     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
804             This->bufsize_frames * fmt->nBlockAlign);
805     if(!This->local_buffer){
806         hr = E_OUTOFMEMORY;
807         goto exit;
808     }
809     if (fmt->wBitsPerSample == 8)
810         memset(This->local_buffer, 128, This->bufsize_frames * fmt->nBlockAlign);
811     else
812         memset(This->local_buffer, 0, This->bufsize_frames * fmt->nBlockAlign);
813
814     if((err = snd_pcm_sw_params_get_boundary(sw_params, &boundary)) < 0){
815         WARN("Unable to get boundary: %d (%s)\n", err, snd_strerror(err));
816         hr = E_FAIL;
817         goto exit;
818     }
819
820     if((err = snd_pcm_sw_params_set_start_threshold(This->pcm_handle,
821                 sw_params, boundary)) < 0){
822         WARN("Unable to set start threshold to %lx: %d (%s)\n", boundary, err,
823                 snd_strerror(err));
824         hr = E_FAIL;
825         goto exit;
826     }
827
828     if((err = snd_pcm_sw_params_set_stop_threshold(This->pcm_handle,
829                 sw_params, boundary)) < 0){
830         WARN("Unable to set stop threshold to %lx: %d (%s)\n", boundary, err,
831                 snd_strerror(err));
832         hr = E_FAIL;
833         goto exit;
834     }
835
836     if((err = snd_pcm_sw_params_set_avail_min(This->pcm_handle,
837                 sw_params, 0)) < 0){
838         WARN("Unable to set avail min to 0: %d (%s)\n", err, snd_strerror(err));
839         hr = E_FAIL;
840         goto exit;
841     }
842
843     if((err = snd_pcm_sw_params(This->pcm_handle, sw_params)) < 0){
844         WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err));
845         hr = E_FAIL;
846         goto exit;
847     }
848
849     if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
850         WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err));
851         hr = E_FAIL;
852         goto exit;
853     }
854
855     if((err = snd_pcm_hw_params_get_buffer_size(This->hw_params,
856                     &This->bufsize_alsa)) < 0){
857         WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err));
858         hr = E_FAIL;
859         goto exit;
860     }
861
862     if((err = snd_pcm_hw_params_get_period_size(This->hw_params,
863                     &This->period_alsa, NULL)) < 0){
864         WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err));
865         hr = E_FAIL;
866         goto exit;
867     }
868
869     if((err = snd_pcm_hw_params_get_period_time(This->hw_params,
870                     &This->period_us, NULL)) < 0){
871         WARN("Unable to get period time: %d (%s)\n", err, snd_strerror(err));
872         hr = E_FAIL;
873         goto exit;
874     }
875
876     This->fmt = clone_format(fmt);
877     if(!This->fmt){
878         hr = E_OUTOFMEMORY;
879         goto exit;
880     }
881
882     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
883     if(!This->vols){
884         hr = E_OUTOFMEMORY;
885         goto exit;
886     }
887
888     for(i = 0; i < fmt->nChannels; ++i)
889         This->vols[i] = 1.f;
890
891     This->share = mode;
892     This->flags = flags;
893
894     EnterCriticalSection(&g_sessions_lock);
895
896     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
897             &This->session);
898     if(FAILED(hr)){
899         LeaveCriticalSection(&g_sessions_lock);
900         goto exit;
901     }
902
903     list_add_tail(&This->session->clients, &This->entry);
904
905     LeaveCriticalSection(&g_sessions_lock);
906
907     This->initted = TRUE;
908
909 exit:
910     HeapFree(GetProcessHeap(), 0, sw_params);
911     if(FAILED(hr)){
912         if(This->local_buffer){
913             HeapFree(GetProcessHeap(), 0, This->local_buffer);
914             This->local_buffer = NULL;
915         }
916         if(This->fmt){
917             CoTaskMemFree(This->fmt);
918             This->fmt = NULL;
919         }
920         if(This->vols){
921             HeapFree(GetProcessHeap(), 0, This->vols);
922             This->vols = NULL;
923         }
924     }
925
926     LeaveCriticalSection(&This->lock);
927
928     return hr;
929 }
930
931 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
932         UINT32 *out)
933 {
934     ACImpl *This = impl_from_IAudioClient(iface);
935
936     TRACE("(%p)->(%p)\n", This, out);
937
938     if(!out)
939         return E_POINTER;
940
941     EnterCriticalSection(&This->lock);
942
943     if(!This->initted){
944         LeaveCriticalSection(&This->lock);
945         return AUDCLNT_E_NOT_INITIALIZED;
946     }
947
948     *out = This->bufsize_frames;
949
950     LeaveCriticalSection(&This->lock);
951
952     return S_OK;
953 }
954
955 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
956         REFERENCE_TIME *latency)
957 {
958     ACImpl *This = impl_from_IAudioClient(iface);
959
960     TRACE("(%p)->(%p)\n", This, latency);
961
962     if(!latency)
963         return E_POINTER;
964
965     EnterCriticalSection(&This->lock);
966
967     if(!This->initted){
968         LeaveCriticalSection(&This->lock);
969         return AUDCLNT_E_NOT_INITIALIZED;
970     }
971
972     LeaveCriticalSection(&This->lock);
973
974     *latency = 500000;
975
976     return S_OK;
977 }
978
979 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
980         UINT32 *out)
981 {
982     ACImpl *This = impl_from_IAudioClient(iface);
983
984     TRACE("(%p)->(%p)\n", This, out);
985
986     if(!out)
987         return E_POINTER;
988
989     EnterCriticalSection(&This->lock);
990
991     if(!This->initted){
992         LeaveCriticalSection(&This->lock);
993         return AUDCLNT_E_NOT_INITIALIZED;
994     }
995
996     if(This->dataflow == eRender){
997         snd_pcm_sframes_t avail_frames;
998
999         avail_frames = snd_pcm_avail_update(This->pcm_handle);
1000
1001         if(This->bufsize_alsa < avail_frames){
1002             WARN("Xrun detected\n");
1003             *out = This->held_frames;
1004         }else
1005             *out = This->bufsize_alsa - avail_frames + This->held_frames;
1006     }else if(This->dataflow == eCapture){
1007         *out = This->held_frames;
1008     }else{
1009         LeaveCriticalSection(&This->lock);
1010         return E_UNEXPECTED;
1011     }
1012
1013     LeaveCriticalSection(&This->lock);
1014
1015     return S_OK;
1016 }
1017
1018 static DWORD get_channel_mask(unsigned int channels)
1019 {
1020     switch(channels){
1021     case 0:
1022         return 0;
1023     case 1:
1024         return SPEAKER_FRONT_CENTER;
1025     case 2:
1026         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1027     case 3:
1028         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
1029             SPEAKER_LOW_FREQUENCY;
1030     case 4:
1031         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
1032             SPEAKER_BACK_RIGHT;
1033     case 5:
1034         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
1035             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
1036     case 6:
1037         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
1038             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
1039     case 7:
1040         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
1041             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
1042             SPEAKER_BACK_CENTER;
1043     }
1044     FIXME("Unknown speaker configuration: %u\n", channels);
1045     return 0;
1046 }
1047
1048 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1049         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt,
1050         WAVEFORMATEX **out)
1051 {
1052     ACImpl *This = impl_from_IAudioClient(iface);
1053     snd_pcm_format_mask_t *formats = NULL;
1054     HRESULT hr = S_OK;
1055     WAVEFORMATEX *closest = NULL;
1056     const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt;
1057     unsigned int max = 0, min = 0;
1058     int err;
1059
1060     TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
1061
1062     if(!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
1063         return E_POINTER;
1064
1065     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1066         return E_INVALIDARG;
1067
1068     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1069             fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1070         return E_INVALIDARG;
1071
1072     dump_fmt(fmt);
1073
1074     EnterCriticalSection(&This->lock);
1075
1076     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1077         hr = E_FAIL;
1078         goto exit;
1079     }
1080
1081     formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1082             snd_pcm_format_mask_sizeof());
1083     if(!formats){
1084         hr = E_OUTOFMEMORY;
1085         goto exit;
1086     }
1087
1088     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1089
1090     if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
1091             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1092              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
1093         switch(fmt->wBitsPerSample){
1094         case 8:
1095             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
1096                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1097                 goto exit;
1098             }
1099             break;
1100         case 16:
1101             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
1102                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1103                 goto exit;
1104             }
1105             break;
1106         case 24:
1107             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
1108                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1109                 goto exit;
1110             }
1111             break;
1112         case 32:
1113             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
1114                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1115                 goto exit;
1116             }
1117             break;
1118         default:
1119             hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1120             goto exit;
1121         }
1122     }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
1123             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1124              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
1125         switch(fmt->wBitsPerSample){
1126         case 32:
1127             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
1128                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1129                 goto exit;
1130             }
1131             break;
1132         case 64:
1133             if(!snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT64_LE)){
1134                 hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1135                 goto exit;
1136             }
1137             break;
1138         default:
1139             hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1140             goto exit;
1141         }
1142     }else{
1143         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1144         goto exit;
1145     }
1146
1147     closest = clone_format(fmt);
1148     if(!closest){
1149         hr = E_OUTOFMEMORY;
1150         goto exit;
1151     }
1152
1153     if((err = snd_pcm_hw_params_get_rate_min(This->hw_params, &min, NULL)) < 0){
1154         hr = E_FAIL;
1155         WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err));
1156         goto exit;
1157     }
1158
1159     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max, NULL)) < 0){
1160         hr = E_FAIL;
1161         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1162         goto exit;
1163     }
1164
1165     if(fmt->nSamplesPerSec < min || fmt->nSamplesPerSec > max){
1166         hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
1167         goto exit;
1168     }
1169
1170     if((err = snd_pcm_hw_params_get_channels_min(This->hw_params, &min)) < 0){
1171         hr = E_FAIL;
1172         WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err));
1173         goto exit;
1174     }
1175
1176     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params, &max)) < 0){
1177         hr = E_FAIL;
1178         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1179         goto exit;
1180     }
1181     if(max > 7)
1182         max = 2;
1183     if(fmt->nChannels > max){
1184         hr = S_FALSE;
1185         closest->nChannels = max;
1186     }else if(fmt->nChannels < min){
1187         hr = S_FALSE;
1188         closest->nChannels = min;
1189     }
1190
1191     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
1192         DWORD mask = get_channel_mask(closest->nChannels);
1193
1194         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
1195
1196         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1197                 fmtex->dwChannelMask != mask)
1198             hr = S_FALSE;
1199     }
1200
1201 exit:
1202     LeaveCriticalSection(&This->lock);
1203     HeapFree(GetProcessHeap(), 0, formats);
1204
1205     if(hr == S_OK || !out){
1206         CoTaskMemFree(closest);
1207         if(out)
1208             *out = NULL;
1209     }else if(closest){
1210         closest->nBlockAlign =
1211             closest->nChannels * closest->wBitsPerSample / 8;
1212         closest->nAvgBytesPerSec =
1213             closest->nBlockAlign * closest->nSamplesPerSec;
1214         *out = closest;
1215     }
1216
1217     TRACE("returning: %08x\n", hr);
1218     return hr;
1219 }
1220
1221 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1222         WAVEFORMATEX **pwfx)
1223 {
1224     ACImpl *This = impl_from_IAudioClient(iface);
1225     WAVEFORMATEXTENSIBLE *fmt;
1226     snd_pcm_format_mask_t *formats;
1227     unsigned int max_rate, max_channels;
1228     int err;
1229     HRESULT hr = S_OK;
1230
1231     TRACE("(%p)->(%p)\n", This, pwfx);
1232
1233     if(!pwfx)
1234         return E_POINTER;
1235     *pwfx = NULL;
1236
1237     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1238     if(!fmt)
1239         return E_OUTOFMEMORY;
1240
1241     formats = HeapAlloc(GetProcessHeap(), 0, snd_pcm_format_mask_sizeof());
1242     if(!formats){
1243         CoTaskMemFree(fmt);
1244         return E_OUTOFMEMORY;
1245     }
1246
1247     EnterCriticalSection(&This->lock);
1248
1249     if((err = snd_pcm_hw_params_any(This->pcm_handle, This->hw_params)) < 0){
1250         WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err));
1251         hr = E_FAIL;
1252         goto exit;
1253     }
1254
1255     snd_pcm_hw_params_get_format_mask(This->hw_params, formats);
1256
1257     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1258     if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){
1259         fmt->Format.wBitsPerSample = 32;
1260         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1261     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){
1262         fmt->Format.wBitsPerSample = 16;
1263         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1264     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){
1265         fmt->Format.wBitsPerSample = 8;
1266         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1267     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){
1268         fmt->Format.wBitsPerSample = 32;
1269         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1270     }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){
1271         fmt->Format.wBitsPerSample = 24;
1272         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1273     }else{
1274         ERR("Didn't recognize any available ALSA formats\n");
1275         hr = E_FAIL;
1276         goto exit;
1277     }
1278
1279     if((err = snd_pcm_hw_params_get_channels_max(This->hw_params,
1280                     &max_channels)) < 0){
1281         WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err));
1282         hr = E_FAIL;
1283         goto exit;
1284     }
1285
1286     if(max_channels > 2){
1287         FIXME("Don't know what to do with %u channels, pretending there's "
1288                 "only 2 channels\n", max_channels);
1289         fmt->Format.nChannels = 2;
1290     }else
1291         fmt->Format.nChannels = max_channels;
1292
1293     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1294
1295     if((err = snd_pcm_hw_params_get_rate_max(This->hw_params, &max_rate,
1296                     NULL)) < 0){
1297         WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err));
1298         hr = E_FAIL;
1299         goto exit;
1300     }
1301
1302     if(max_rate >= 48000)
1303         fmt->Format.nSamplesPerSec = 48000;
1304     else if(max_rate >= 44100)
1305         fmt->Format.nSamplesPerSec = 44100;
1306     else if(max_rate >= 22050)
1307         fmt->Format.nSamplesPerSec = 22050;
1308     else if(max_rate >= 11025)
1309         fmt->Format.nSamplesPerSec = 11025;
1310     else if(max_rate >= 8000)
1311         fmt->Format.nSamplesPerSec = 8000;
1312     else{
1313         ERR("Unknown max rate: %u\n", max_rate);
1314         hr = E_FAIL;
1315         goto exit;
1316     }
1317
1318     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1319             fmt->Format.nChannels) / 8;
1320     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1321         fmt->Format.nBlockAlign;
1322
1323     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1324     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1325
1326     dump_fmt((WAVEFORMATEX*)fmt);
1327     *pwfx = (WAVEFORMATEX*)fmt;
1328
1329 exit:
1330     LeaveCriticalSection(&This->lock);
1331     if(FAILED(hr))
1332         CoTaskMemFree(fmt);
1333     HeapFree(GetProcessHeap(), 0, formats);
1334
1335     return hr;
1336 }
1337
1338 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1339         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1340 {
1341     ACImpl *This = impl_from_IAudioClient(iface);
1342
1343     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1344
1345     if(!defperiod && !minperiod)
1346         return E_POINTER;
1347
1348     if(defperiod)
1349         *defperiod = DefaultPeriod;
1350     if(minperiod)
1351         *minperiod = MinimumPeriod;
1352
1353     return S_OK;
1354 }
1355
1356 static snd_pcm_sframes_t alsa_write_best_effort(snd_pcm_t *handle, BYTE *buf,
1357         snd_pcm_uframes_t frames, ACImpl *This)
1358 {
1359     snd_pcm_sframes_t written;
1360
1361     if(This->session->mute){
1362         int err;
1363         if((err = snd_pcm_format_set_silence(This->alsa_format, buf,
1364                         frames * This->fmt->nChannels)) < 0)
1365             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1366                     snd_strerror(err));
1367     }
1368
1369     written = snd_pcm_writei(handle, buf, frames);
1370     if(written < 0){
1371         int ret;
1372
1373         if(written == -EAGAIN)
1374             /* buffer full */
1375             return 0;
1376
1377         WARN("writei failed, recovering: %ld (%s)\n", written,
1378                 snd_strerror(written));
1379
1380         ret = wine_snd_pcm_recover(handle, written, 0);
1381         if(ret < 0){
1382             WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret));
1383             return ret;
1384         }
1385
1386         written = snd_pcm_writei(handle, buf, frames);
1387     }
1388
1389     return written;
1390 }
1391
1392 static void alsa_write_data(ACImpl *This)
1393 {
1394     snd_pcm_sframes_t written;
1395     snd_pcm_uframes_t to_write;
1396     BYTE *buf =
1397         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1398
1399     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1400         to_write = This->bufsize_frames - This->lcl_offs_frames;
1401     else
1402         to_write = This->held_frames;
1403
1404     written = alsa_write_best_effort(This->pcm_handle, buf, to_write, This);
1405     if(written < 0){
1406         WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1407         return;
1408     }
1409
1410     This->lcl_offs_frames += written;
1411     This->lcl_offs_frames %= This->bufsize_frames;
1412     This->held_frames -= written;
1413
1414     if(written < to_write){
1415         /* ALSA buffer probably full */
1416         return;
1417     }
1418
1419     if(This->held_frames){
1420         /* wrapped and have some data back at the start to write */
1421         written = alsa_write_best_effort(This->pcm_handle, This->local_buffer,
1422                 This->held_frames, This);
1423         if(written < 0){
1424             WARN("Couldn't write: %ld (%s)\n", written, snd_strerror(written));
1425             return;
1426         }
1427
1428         This->lcl_offs_frames += written;
1429         This->lcl_offs_frames %= This->bufsize_frames;
1430         This->held_frames -= written;
1431     }
1432 }
1433
1434 static void alsa_read_data(ACImpl *This)
1435 {
1436     snd_pcm_sframes_t pos, readable, nread;
1437
1438     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1439     readable = This->bufsize_frames - pos;
1440
1441     nread = snd_pcm_readi(This->pcm_handle,
1442             This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1443     if(nread < 0){
1444         int ret;
1445
1446         WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread));
1447
1448         ret = wine_snd_pcm_recover(This->pcm_handle, nread, 0);
1449         if(ret < 0){
1450             WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret));
1451             return;
1452         }
1453
1454         nread = snd_pcm_readi(This->pcm_handle,
1455                 This->local_buffer + pos * This->fmt->nBlockAlign, readable);
1456         if(nread < 0){
1457             WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread));
1458             return;
1459         }
1460     }
1461
1462     if(This->session->mute){
1463         int err;
1464         if((err = snd_pcm_format_set_silence(This->alsa_format,
1465                         This->local_buffer + pos * This->fmt->nBlockAlign,
1466                         nread)) < 0)
1467             WARN("Setting buffer to silence failed: %d (%s)\n", err,
1468                     snd_strerror(err));
1469     }
1470
1471     This->held_frames += nread;
1472
1473     if(This->held_frames > This->bufsize_frames){
1474         WARN("Overflow of unread data\n");
1475         This->lcl_offs_frames += This->held_frames;
1476         This->lcl_offs_frames %= This->bufsize_frames;
1477         This->held_frames = This->bufsize_frames;
1478     }
1479 }
1480
1481 static void CALLBACK alsa_push_buffer_data(void *user, BOOLEAN timer)
1482 {
1483     ACImpl *This = user;
1484
1485     EnterCriticalSection(&This->lock);
1486
1487     if(This->started){
1488         if(This->dataflow == eRender && This->held_frames)
1489             alsa_write_data(This);
1490         else if(This->dataflow == eCapture)
1491             alsa_read_data(This);
1492
1493         if(This->event)
1494             SetEvent(This->event);
1495     }
1496
1497     LeaveCriticalSection(&This->lock);
1498 }
1499
1500 static HRESULT alsa_consider_start(ACImpl *This)
1501 {
1502     snd_pcm_sframes_t avail;
1503     int err;
1504
1505     avail = snd_pcm_avail_update(This->pcm_handle);
1506     if(avail < 0){
1507         WARN("Unable to get avail_update: %ld (%s)\n", avail,
1508                 snd_strerror(avail));
1509         return E_FAIL;
1510     }
1511
1512     if(This->period_alsa < This->bufsize_alsa - avail){
1513         if((err = snd_pcm_start(This->pcm_handle)) < 0){
1514             WARN("Start failed: %d (%s), state: %d\n", err, snd_strerror(err),
1515                     snd_pcm_state(This->pcm_handle));
1516             return E_FAIL;
1517         }
1518
1519         return S_OK;
1520     }
1521
1522     return S_FALSE;
1523 }
1524
1525 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1526 {
1527     ACImpl *This = impl_from_IAudioClient(iface);
1528     DWORD period_ms;
1529     HRESULT hr;
1530
1531     TRACE("(%p)\n", This);
1532
1533     EnterCriticalSection(&This->lock);
1534
1535     if(!This->initted){
1536         LeaveCriticalSection(&This->lock);
1537         return AUDCLNT_E_NOT_INITIALIZED;
1538     }
1539
1540     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1541         LeaveCriticalSection(&This->lock);
1542         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1543     }
1544
1545     if(This->started){
1546         LeaveCriticalSection(&This->lock);
1547         return AUDCLNT_E_NOT_STOPPED;
1548     }
1549
1550     hr = alsa_consider_start(This);
1551     if(FAILED(hr)){
1552         LeaveCriticalSection(&This->lock);
1553         return hr;
1554     }
1555
1556     period_ms = This->period_us / 1000;
1557     if(!period_ms)
1558         period_ms = 10;
1559
1560     if(This->dataflow == eCapture){
1561         /* dump any data that might be leftover in the ALSA capture buffer */
1562         snd_pcm_readi(This->pcm_handle, This->local_buffer,
1563                 This->bufsize_frames);
1564     }
1565
1566     if(!CreateTimerQueueTimer(&This->timer, g_timer_q, alsa_push_buffer_data,
1567             This, 0, period_ms, WT_EXECUTEINTIMERTHREAD)){
1568         LeaveCriticalSection(&This->lock);
1569         WARN("Unable to create timer: %u\n", GetLastError());
1570         return E_FAIL;
1571     }
1572
1573     This->started = TRUE;
1574
1575     LeaveCriticalSection(&This->lock);
1576
1577     return S_OK;
1578 }
1579
1580 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1581 {
1582     ACImpl *This = impl_from_IAudioClient(iface);
1583     int err;
1584     HANDLE event;
1585     BOOL wait;
1586
1587     TRACE("(%p)\n", This);
1588
1589     EnterCriticalSection(&This->lock);
1590
1591     if(!This->initted){
1592         LeaveCriticalSection(&This->lock);
1593         return AUDCLNT_E_NOT_INITIALIZED;
1594     }
1595
1596     if(!This->started){
1597         LeaveCriticalSection(&This->lock);
1598         return S_FALSE;
1599     }
1600
1601     event = CreateEventW(NULL, TRUE, FALSE, NULL);
1602     wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event);
1603     if(wait)
1604         WARN("DeleteTimerQueueTimer error %u\n", GetLastError());
1605     wait = wait && GetLastError() == ERROR_IO_PENDING;
1606
1607     if((err = snd_pcm_drop(This->pcm_handle)) < 0){
1608         LeaveCriticalSection(&This->lock);
1609         WARN("Drop failed: %d (%s)\n", err, snd_strerror(err));
1610         return E_FAIL;
1611     }
1612
1613     if((err = snd_pcm_prepare(This->pcm_handle)) < 0){
1614         LeaveCriticalSection(&This->lock);
1615         WARN("Prepare failed: %d (%s)\n", err, snd_strerror(err));
1616         return E_FAIL;
1617     }
1618
1619     This->started = FALSE;
1620
1621     LeaveCriticalSection(&This->lock);
1622
1623     if(event && wait)
1624         WaitForSingleObject(event, INFINITE);
1625     CloseHandle(event);
1626
1627     return S_OK;
1628 }
1629
1630 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1631 {
1632     ACImpl *This = impl_from_IAudioClient(iface);
1633
1634     TRACE("(%p)\n", This);
1635
1636     EnterCriticalSection(&This->lock);
1637
1638     if(!This->initted){
1639         LeaveCriticalSection(&This->lock);
1640         return AUDCLNT_E_NOT_INITIALIZED;
1641     }
1642
1643     if(This->started){
1644         LeaveCriticalSection(&This->lock);
1645         return AUDCLNT_E_NOT_STOPPED;
1646     }
1647
1648     This->held_frames = 0;
1649     This->written_frames = 0;
1650     This->lcl_offs_frames = 0;
1651
1652     LeaveCriticalSection(&This->lock);
1653
1654     return S_OK;
1655 }
1656
1657 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1658         HANDLE event)
1659 {
1660     ACImpl *This = impl_from_IAudioClient(iface);
1661
1662     TRACE("(%p)->(%p)\n", This, event);
1663
1664     if(!event)
1665         return E_INVALIDARG;
1666
1667     EnterCriticalSection(&This->lock);
1668
1669     if(!This->initted){
1670         LeaveCriticalSection(&This->lock);
1671         return AUDCLNT_E_NOT_INITIALIZED;
1672     }
1673
1674     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1675         LeaveCriticalSection(&This->lock);
1676         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1677     }
1678
1679     This->event = event;
1680
1681     LeaveCriticalSection(&This->lock);
1682
1683     return S_OK;
1684 }
1685
1686 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1687         void **ppv)
1688 {
1689     ACImpl *This = impl_from_IAudioClient(iface);
1690
1691     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1692
1693     if(!ppv)
1694         return E_POINTER;
1695     *ppv = NULL;
1696
1697     EnterCriticalSection(&This->lock);
1698
1699     if(!This->initted){
1700         LeaveCriticalSection(&This->lock);
1701         return AUDCLNT_E_NOT_INITIALIZED;
1702     }
1703
1704     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1705         if(This->dataflow != eRender){
1706             LeaveCriticalSection(&This->lock);
1707             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1708         }
1709         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1710         *ppv = &This->IAudioRenderClient_iface;
1711     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1712         if(This->dataflow != eCapture){
1713             LeaveCriticalSection(&This->lock);
1714             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1715         }
1716         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1717         *ppv = &This->IAudioCaptureClient_iface;
1718     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1719         IAudioClock_AddRef(&This->IAudioClock_iface);
1720         *ppv = &This->IAudioClock_iface;
1721     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1722         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1723         *ppv = &This->IAudioStreamVolume_iface;
1724     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1725         if(!This->session_wrapper){
1726             This->session_wrapper = AudioSessionWrapper_Create(This);
1727             if(!This->session_wrapper){
1728                 LeaveCriticalSection(&This->lock);
1729                 return E_OUTOFMEMORY;
1730             }
1731         }else
1732             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1733
1734         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1735     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1736         if(!This->session_wrapper){
1737             This->session_wrapper = AudioSessionWrapper_Create(This);
1738             if(!This->session_wrapper){
1739                 LeaveCriticalSection(&This->lock);
1740                 return E_OUTOFMEMORY;
1741             }
1742         }else
1743             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1744
1745         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1746     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1747         if(!This->session_wrapper){
1748             This->session_wrapper = AudioSessionWrapper_Create(This);
1749             if(!This->session_wrapper){
1750                 LeaveCriticalSection(&This->lock);
1751                 return E_OUTOFMEMORY;
1752             }
1753         }else
1754             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1755
1756         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1757     }
1758
1759     if(*ppv){
1760         LeaveCriticalSection(&This->lock);
1761         return S_OK;
1762     }
1763
1764     LeaveCriticalSection(&This->lock);
1765
1766     FIXME("stub %s\n", debugstr_guid(riid));
1767     return E_NOINTERFACE;
1768 }
1769
1770 static const IAudioClientVtbl AudioClient_Vtbl =
1771 {
1772     AudioClient_QueryInterface,
1773     AudioClient_AddRef,
1774     AudioClient_Release,
1775     AudioClient_Initialize,
1776     AudioClient_GetBufferSize,
1777     AudioClient_GetStreamLatency,
1778     AudioClient_GetCurrentPadding,
1779     AudioClient_IsFormatSupported,
1780     AudioClient_GetMixFormat,
1781     AudioClient_GetDevicePeriod,
1782     AudioClient_Start,
1783     AudioClient_Stop,
1784     AudioClient_Reset,
1785     AudioClient_SetEventHandle,
1786     AudioClient_GetService
1787 };
1788
1789 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1790         IAudioRenderClient *iface, REFIID riid, void **ppv)
1791 {
1792     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1793
1794     if(!ppv)
1795         return E_POINTER;
1796     *ppv = NULL;
1797
1798     if(IsEqualIID(riid, &IID_IUnknown) ||
1799             IsEqualIID(riid, &IID_IAudioRenderClient))
1800         *ppv = iface;
1801     if(*ppv){
1802         IUnknown_AddRef((IUnknown*)*ppv);
1803         return S_OK;
1804     }
1805
1806     WARN("Unknown interface %s\n", debugstr_guid(riid));
1807     return E_NOINTERFACE;
1808 }
1809
1810 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1811 {
1812     ACImpl *This = impl_from_IAudioRenderClient(iface);
1813     return AudioClient_AddRef(&This->IAudioClient_iface);
1814 }
1815
1816 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1817 {
1818     ACImpl *This = impl_from_IAudioRenderClient(iface);
1819     return AudioClient_Release(&This->IAudioClient_iface);
1820 }
1821
1822 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1823         UINT32 frames, BYTE **data)
1824 {
1825     ACImpl *This = impl_from_IAudioRenderClient(iface);
1826     UINT32 write_pos;
1827     UINT32 pad;
1828     HRESULT hr;
1829
1830     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1831
1832     if(!data)
1833         return E_POINTER;
1834
1835     EnterCriticalSection(&This->lock);
1836
1837     if(This->buf_state != NOT_LOCKED){
1838         LeaveCriticalSection(&This->lock);
1839         return AUDCLNT_E_OUT_OF_ORDER;
1840     }
1841
1842     if(!frames){
1843         This->buf_state = LOCKED_NORMAL;
1844         LeaveCriticalSection(&This->lock);
1845         return S_OK;
1846     }
1847
1848     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1849     if(FAILED(hr)){
1850         LeaveCriticalSection(&This->lock);
1851         return hr;
1852     }
1853
1854     if(pad + frames > This->bufsize_frames){
1855         LeaveCriticalSection(&This->lock);
1856         return AUDCLNT_E_BUFFER_TOO_LARGE;
1857     }
1858
1859     write_pos =
1860         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1861     if(write_pos + frames > This->bufsize_frames){
1862         if(This->tmp_buffer_frames < frames){
1863             if(This->tmp_buffer)
1864                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1865                         This->tmp_buffer, frames * This->fmt->nBlockAlign);
1866             else
1867                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1868                         frames * This->fmt->nBlockAlign);
1869             if(!This->tmp_buffer){
1870                 LeaveCriticalSection(&This->lock);
1871                 return E_OUTOFMEMORY;
1872             }
1873             This->tmp_buffer_frames = frames;
1874         }
1875         *data = This->tmp_buffer;
1876         This->buf_state = LOCKED_WRAPPED;
1877     }else{
1878         *data = This->local_buffer +
1879             This->lcl_offs_frames * This->fmt->nBlockAlign;
1880         This->buf_state = LOCKED_NORMAL;
1881     }
1882
1883     LeaveCriticalSection(&This->lock);
1884
1885     return S_OK;
1886 }
1887
1888 static void alsa_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1889 {
1890     snd_pcm_uframes_t write_offs_frames =
1891         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1892     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1893     snd_pcm_uframes_t chunk_frames = This->bufsize_frames - write_offs_frames;
1894     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1895
1896     if(written_bytes < chunk_bytes){
1897         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1898     }else{
1899         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1900         memcpy(This->local_buffer, buffer + chunk_bytes,
1901                 written_bytes - chunk_bytes);
1902     }
1903 }
1904
1905 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1906         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1907 {
1908     ACImpl *This = impl_from_IAudioRenderClient(iface);
1909     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1910     BYTE *buffer;
1911     HRESULT hr;
1912
1913     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1914
1915     EnterCriticalSection(&This->lock);
1916
1917     if(This->buf_state == NOT_LOCKED || !written_frames){
1918         This->buf_state = NOT_LOCKED;
1919         LeaveCriticalSection(&This->lock);
1920         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1921     }
1922
1923     if(This->buf_state == LOCKED_NORMAL)
1924         buffer = This->local_buffer +
1925             This->lcl_offs_frames * This->fmt->nBlockAlign;
1926     else
1927         buffer = This->tmp_buffer;
1928
1929     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1930         WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1931         if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1932                 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1933                  IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1934                 This->fmt->wBitsPerSample == 8)
1935             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1936         else
1937             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1938     }
1939
1940     if(This->held_frames){
1941         if(This->buf_state == LOCKED_WRAPPED)
1942             alsa_wrap_buffer(This, buffer, written_bytes);
1943
1944         This->held_frames += written_frames;
1945     }else{
1946         snd_pcm_sframes_t written;
1947
1948         written = alsa_write_best_effort(This->pcm_handle, buffer,
1949                 written_frames, This);
1950         if(written < 0){
1951             LeaveCriticalSection(&This->lock);
1952             WARN("write failed: %ld (%s)\n", written, snd_strerror(written));
1953             return E_FAIL;
1954         }
1955
1956         if(written < written_frames){
1957             if(This->buf_state == LOCKED_WRAPPED)
1958                 alsa_wrap_buffer(This,
1959                         This->tmp_buffer + written * This->fmt->nBlockAlign,
1960                         written_frames - written);
1961
1962             This->held_frames = written_frames - written;
1963         }
1964     }
1965
1966     if(This->started &&
1967             snd_pcm_state(This->pcm_handle) == SND_PCM_STATE_PREPARED){
1968         hr = alsa_consider_start(This);
1969         if(FAILED(hr)){
1970             LeaveCriticalSection(&This->lock);
1971             return hr;
1972         }
1973     }
1974
1975     This->written_frames += written_frames;
1976     This->buf_state = NOT_LOCKED;
1977
1978     LeaveCriticalSection(&This->lock);
1979
1980     return S_OK;
1981 }
1982
1983 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1984     AudioRenderClient_QueryInterface,
1985     AudioRenderClient_AddRef,
1986     AudioRenderClient_Release,
1987     AudioRenderClient_GetBuffer,
1988     AudioRenderClient_ReleaseBuffer
1989 };
1990
1991 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1992         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1993 {
1994     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1995
1996     if(!ppv)
1997         return E_POINTER;
1998     *ppv = NULL;
1999
2000     if(IsEqualIID(riid, &IID_IUnknown) ||
2001             IsEqualIID(riid, &IID_IAudioCaptureClient))
2002         *ppv = iface;
2003     if(*ppv){
2004         IUnknown_AddRef((IUnknown*)*ppv);
2005         return S_OK;
2006     }
2007
2008     WARN("Unknown interface %s\n", debugstr_guid(riid));
2009     return E_NOINTERFACE;
2010 }
2011
2012 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
2013 {
2014     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2015     return IAudioClient_AddRef(&This->IAudioClient_iface);
2016 }
2017
2018 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
2019 {
2020     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2021     return IAudioClient_Release(&This->IAudioClient_iface);
2022 }
2023
2024 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
2025         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
2026         UINT64 *qpcpos)
2027 {
2028     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2029     HRESULT hr;
2030
2031     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
2032             devpos, qpcpos);
2033
2034     if(!data || !frames || !flags)
2035         return E_POINTER;
2036
2037     EnterCriticalSection(&This->lock);
2038
2039     if(This->buf_state != NOT_LOCKED){
2040         LeaveCriticalSection(&This->lock);
2041         return AUDCLNT_E_OUT_OF_ORDER;
2042     }
2043
2044     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
2045     if(FAILED(hr)){
2046         LeaveCriticalSection(&This->lock);
2047         return hr;
2048     }
2049
2050     *flags = 0;
2051
2052     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
2053         UINT32 chunk_bytes, offs_bytes, frames_bytes;
2054         if(This->tmp_buffer_frames < *frames){
2055             if(This->tmp_buffer)
2056                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
2057                         This->tmp_buffer, *frames * This->fmt->nBlockAlign);
2058             else
2059                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
2060                         *frames * This->fmt->nBlockAlign);
2061             if(!This->tmp_buffer){
2062                 LeaveCriticalSection(&This->lock);
2063                 return E_OUTOFMEMORY;
2064             }
2065             This->tmp_buffer_frames = *frames;
2066         }
2067
2068         *data = This->tmp_buffer;
2069         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
2070             This->fmt->nBlockAlign;
2071         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
2072         frames_bytes = *frames * This->fmt->nBlockAlign;
2073         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
2074         memcpy(This->tmp_buffer + chunk_bytes, This->local_buffer,
2075                 frames_bytes - chunk_bytes);
2076     }else
2077         *data = This->local_buffer +
2078             This->lcl_offs_frames * This->fmt->nBlockAlign;
2079
2080     This->buf_state = LOCKED_NORMAL;
2081
2082     if(devpos || qpcpos)
2083         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
2084
2085     LeaveCriticalSection(&This->lock);
2086
2087     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
2088 }
2089
2090 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
2091         IAudioCaptureClient *iface, UINT32 done)
2092 {
2093     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2094
2095     TRACE("(%p)->(%u)\n", This, done);
2096
2097     EnterCriticalSection(&This->lock);
2098
2099     if(This->buf_state == NOT_LOCKED){
2100         LeaveCriticalSection(&This->lock);
2101         return AUDCLNT_E_OUT_OF_ORDER;
2102     }
2103
2104     This->held_frames -= done;
2105     This->lcl_offs_frames += done;
2106     This->lcl_offs_frames %= This->bufsize_frames;
2107
2108     This->buf_state = NOT_LOCKED;
2109
2110     LeaveCriticalSection(&This->lock);
2111
2112     return S_OK;
2113 }
2114
2115 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
2116         IAudioCaptureClient *iface, UINT32 *frames)
2117 {
2118     ACImpl *This = impl_from_IAudioCaptureClient(iface);
2119
2120     TRACE("(%p)->(%p)\n", This, frames);
2121
2122     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
2123 }
2124
2125 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
2126 {
2127     AudioCaptureClient_QueryInterface,
2128     AudioCaptureClient_AddRef,
2129     AudioCaptureClient_Release,
2130     AudioCaptureClient_GetBuffer,
2131     AudioCaptureClient_ReleaseBuffer,
2132     AudioCaptureClient_GetNextPacketSize
2133 };
2134
2135 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2136         REFIID riid, void **ppv)
2137 {
2138     ACImpl *This = impl_from_IAudioClock(iface);
2139
2140     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2141
2142     if(!ppv)
2143         return E_POINTER;
2144     *ppv = NULL;
2145
2146     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2147         *ppv = iface;
2148     else if(IsEqualIID(riid, &IID_IAudioClock2))
2149         *ppv = &This->IAudioClock2_iface;
2150     if(*ppv){
2151         IUnknown_AddRef((IUnknown*)*ppv);
2152         return S_OK;
2153     }
2154
2155     WARN("Unknown interface %s\n", debugstr_guid(riid));
2156     return E_NOINTERFACE;
2157 }
2158
2159 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2160 {
2161     ACImpl *This = impl_from_IAudioClock(iface);
2162     return IAudioClient_AddRef(&This->IAudioClient_iface);
2163 }
2164
2165 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2166 {
2167     ACImpl *This = impl_from_IAudioClock(iface);
2168     return IAudioClient_Release(&This->IAudioClient_iface);
2169 }
2170
2171 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2172 {
2173     ACImpl *This = impl_from_IAudioClock(iface);
2174
2175     TRACE("(%p)->(%p)\n", This, freq);
2176
2177     *freq = This->fmt->nSamplesPerSec;
2178
2179     return S_OK;
2180 }
2181
2182 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2183         UINT64 *qpctime)
2184 {
2185     ACImpl *This = impl_from_IAudioClock(iface);
2186     UINT32 pad;
2187     HRESULT hr;
2188
2189     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2190
2191     if(!pos)
2192         return E_POINTER;
2193
2194     EnterCriticalSection(&This->lock);
2195
2196     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2197     if(FAILED(hr)){
2198         LeaveCriticalSection(&This->lock);
2199         return hr;
2200     }
2201
2202     if(This->dataflow == eRender)
2203         *pos = This->written_frames - pad;
2204     else if(This->dataflow == eCapture)
2205         *pos = This->written_frames + pad;
2206
2207     LeaveCriticalSection(&This->lock);
2208
2209     if(qpctime){
2210         LARGE_INTEGER stamp, freq;
2211         QueryPerformanceCounter(&stamp);
2212         QueryPerformanceFrequency(&freq);
2213         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2214     }
2215
2216     return S_OK;
2217 }
2218
2219 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2220         DWORD *chars)
2221 {
2222     ACImpl *This = impl_from_IAudioClock(iface);
2223
2224     TRACE("(%p)->(%p)\n", This, chars);
2225
2226     if(!chars)
2227         return E_POINTER;
2228
2229     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2230
2231     return S_OK;
2232 }
2233
2234 static const IAudioClockVtbl AudioClock_Vtbl =
2235 {
2236     AudioClock_QueryInterface,
2237     AudioClock_AddRef,
2238     AudioClock_Release,
2239     AudioClock_GetFrequency,
2240     AudioClock_GetPosition,
2241     AudioClock_GetCharacteristics
2242 };
2243
2244 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2245         REFIID riid, void **ppv)
2246 {
2247     ACImpl *This = impl_from_IAudioClock2(iface);
2248     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2249 }
2250
2251 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2252 {
2253     ACImpl *This = impl_from_IAudioClock2(iface);
2254     return IAudioClient_AddRef(&This->IAudioClient_iface);
2255 }
2256
2257 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2258 {
2259     ACImpl *This = impl_from_IAudioClock2(iface);
2260     return IAudioClient_Release(&This->IAudioClient_iface);
2261 }
2262
2263 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2264         UINT64 *pos, UINT64 *qpctime)
2265 {
2266     ACImpl *This = impl_from_IAudioClock2(iface);
2267
2268     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2269
2270     return E_NOTIMPL;
2271 }
2272
2273 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2274 {
2275     AudioClock2_QueryInterface,
2276     AudioClock2_AddRef,
2277     AudioClock2_Release,
2278     AudioClock2_GetDevicePosition
2279 };
2280
2281 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2282 {
2283     AudioSessionWrapper *ret;
2284
2285     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2286             sizeof(AudioSessionWrapper));
2287     if(!ret)
2288         return NULL;
2289
2290     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2291     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2292     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2293
2294     ret->ref = 1;
2295
2296     ret->client = client;
2297     if(client){
2298         ret->session = client->session;
2299         AudioClient_AddRef(&client->IAudioClient_iface);
2300     }
2301
2302     return ret;
2303 }
2304
2305 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2306         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2307 {
2308     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2309
2310     if(!ppv)
2311         return E_POINTER;
2312     *ppv = NULL;
2313
2314     if(IsEqualIID(riid, &IID_IUnknown) ||
2315             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2316             IsEqualIID(riid, &IID_IAudioSessionControl2))
2317         *ppv = iface;
2318     if(*ppv){
2319         IUnknown_AddRef((IUnknown*)*ppv);
2320         return S_OK;
2321     }
2322
2323     WARN("Unknown interface %s\n", debugstr_guid(riid));
2324     return E_NOINTERFACE;
2325 }
2326
2327 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2328 {
2329     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2330     ULONG ref;
2331     ref = InterlockedIncrement(&This->ref);
2332     TRACE("(%p) Refcount now %u\n", This, ref);
2333     return ref;
2334 }
2335
2336 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2337 {
2338     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2339     ULONG ref;
2340     ref = InterlockedDecrement(&This->ref);
2341     TRACE("(%p) Refcount now %u\n", This, ref);
2342     if(!ref){
2343         if(This->client){
2344             EnterCriticalSection(&This->client->lock);
2345             This->client->session_wrapper = NULL;
2346             LeaveCriticalSection(&This->client->lock);
2347             AudioClient_Release(&This->client->IAudioClient_iface);
2348         }
2349         HeapFree(GetProcessHeap(), 0, This);
2350     }
2351     return ref;
2352 }
2353
2354 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2355         AudioSessionState *state)
2356 {
2357     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2358     ACImpl *client;
2359
2360     TRACE("(%p)->(%p)\n", This, state);
2361
2362     if(!state)
2363         return NULL_PTR_ERR;
2364
2365     EnterCriticalSection(&g_sessions_lock);
2366
2367     if(list_empty(&This->session->clients)){
2368         *state = AudioSessionStateExpired;
2369         LeaveCriticalSection(&g_sessions_lock);
2370         return S_OK;
2371     }
2372
2373     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2374         EnterCriticalSection(&client->lock);
2375         if(client->started){
2376             *state = AudioSessionStateActive;
2377             LeaveCriticalSection(&client->lock);
2378             LeaveCriticalSection(&g_sessions_lock);
2379             return S_OK;
2380         }
2381         LeaveCriticalSection(&client->lock);
2382     }
2383
2384     LeaveCriticalSection(&g_sessions_lock);
2385
2386     *state = AudioSessionStateInactive;
2387
2388     return S_OK;
2389 }
2390
2391 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2392         IAudioSessionControl2 *iface, WCHAR **name)
2393 {
2394     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2395
2396     FIXME("(%p)->(%p) - stub\n", This, name);
2397
2398     return E_NOTIMPL;
2399 }
2400
2401 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2402         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2403 {
2404     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2405
2406     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2407
2408     return E_NOTIMPL;
2409 }
2410
2411 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2412         IAudioSessionControl2 *iface, WCHAR **path)
2413 {
2414     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2415
2416     FIXME("(%p)->(%p) - stub\n", This, path);
2417
2418     return E_NOTIMPL;
2419 }
2420
2421 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2422         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2423 {
2424     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2425
2426     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2427
2428     return E_NOTIMPL;
2429 }
2430
2431 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2432         IAudioSessionControl2 *iface, GUID *group)
2433 {
2434     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2435
2436     FIXME("(%p)->(%p) - stub\n", This, group);
2437
2438     return E_NOTIMPL;
2439 }
2440
2441 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2442         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2443 {
2444     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2445
2446     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2447             debugstr_guid(session));
2448
2449     return E_NOTIMPL;
2450 }
2451
2452 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2453         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2454 {
2455     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2456
2457     FIXME("(%p)->(%p) - stub\n", This, events);
2458
2459     return S_OK;
2460 }
2461
2462 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2463         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2464 {
2465     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2466
2467     FIXME("(%p)->(%p) - stub\n", This, events);
2468
2469     return S_OK;
2470 }
2471
2472 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2473         IAudioSessionControl2 *iface, WCHAR **id)
2474 {
2475     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2476
2477     FIXME("(%p)->(%p) - stub\n", This, id);
2478
2479     return E_NOTIMPL;
2480 }
2481
2482 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2483         IAudioSessionControl2 *iface, WCHAR **id)
2484 {
2485     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2486
2487     FIXME("(%p)->(%p) - stub\n", This, id);
2488
2489     return E_NOTIMPL;
2490 }
2491
2492 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2493         IAudioSessionControl2 *iface, DWORD *pid)
2494 {
2495     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2496
2497     TRACE("(%p)->(%p)\n", This, pid);
2498
2499     if(!pid)
2500         return E_POINTER;
2501
2502     *pid = GetCurrentProcessId();
2503
2504     return S_OK;
2505 }
2506
2507 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2508         IAudioSessionControl2 *iface)
2509 {
2510     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2511
2512     TRACE("(%p)\n", This);
2513
2514     return S_FALSE;
2515 }
2516
2517 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2518         IAudioSessionControl2 *iface, BOOL optout)
2519 {
2520     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2521
2522     TRACE("(%p)->(%d)\n", This, optout);
2523
2524     return S_OK;
2525 }
2526
2527 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2528 {
2529     AudioSessionControl_QueryInterface,
2530     AudioSessionControl_AddRef,
2531     AudioSessionControl_Release,
2532     AudioSessionControl_GetState,
2533     AudioSessionControl_GetDisplayName,
2534     AudioSessionControl_SetDisplayName,
2535     AudioSessionControl_GetIconPath,
2536     AudioSessionControl_SetIconPath,
2537     AudioSessionControl_GetGroupingParam,
2538     AudioSessionControl_SetGroupingParam,
2539     AudioSessionControl_RegisterAudioSessionNotification,
2540     AudioSessionControl_UnregisterAudioSessionNotification,
2541     AudioSessionControl_GetSessionIdentifier,
2542     AudioSessionControl_GetSessionInstanceIdentifier,
2543     AudioSessionControl_GetProcessId,
2544     AudioSessionControl_IsSystemSoundsSession,
2545     AudioSessionControl_SetDuckingPreference
2546 };
2547
2548 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2549         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2550 {
2551     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2552
2553     if(!ppv)
2554         return E_POINTER;
2555     *ppv = NULL;
2556
2557     if(IsEqualIID(riid, &IID_IUnknown) ||
2558             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2559         *ppv = iface;
2560     if(*ppv){
2561         IUnknown_AddRef((IUnknown*)*ppv);
2562         return S_OK;
2563     }
2564
2565     WARN("Unknown interface %s\n", debugstr_guid(riid));
2566     return E_NOINTERFACE;
2567 }
2568
2569 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2570 {
2571     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2572     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2573 }
2574
2575 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2576 {
2577     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2578     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2579 }
2580
2581 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2582         ISimpleAudioVolume *iface, float level, const GUID *context)
2583 {
2584     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2585     AudioSession *session = This->session;
2586
2587     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2588
2589     if(level < 0.f || level > 1.f)
2590         return E_INVALIDARG;
2591
2592     if(context)
2593         FIXME("Notifications not supported yet\n");
2594
2595     TRACE("ALSA does not support volume control\n");
2596
2597     EnterCriticalSection(&session->lock);
2598
2599     session->master_vol = level;
2600
2601     LeaveCriticalSection(&session->lock);
2602
2603     return S_OK;
2604 }
2605
2606 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2607         ISimpleAudioVolume *iface, float *level)
2608 {
2609     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2610     AudioSession *session = This->session;
2611
2612     TRACE("(%p)->(%p)\n", session, level);
2613
2614     if(!level)
2615         return NULL_PTR_ERR;
2616
2617     *level = session->master_vol;
2618
2619     return S_OK;
2620 }
2621
2622 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2623         BOOL mute, const GUID *context)
2624 {
2625     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2626     AudioSession *session = This->session;
2627
2628     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2629
2630     if(context)
2631         FIXME("Notifications not supported yet\n");
2632
2633     session->mute = mute;
2634
2635     return S_OK;
2636 }
2637
2638 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2639         BOOL *mute)
2640 {
2641     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2642     AudioSession *session = This->session;
2643
2644     TRACE("(%p)->(%p)\n", session, mute);
2645
2646     if(!mute)
2647         return NULL_PTR_ERR;
2648
2649     *mute = session->mute;
2650
2651     return S_OK;
2652 }
2653
2654 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2655 {
2656     SimpleAudioVolume_QueryInterface,
2657     SimpleAudioVolume_AddRef,
2658     SimpleAudioVolume_Release,
2659     SimpleAudioVolume_SetMasterVolume,
2660     SimpleAudioVolume_GetMasterVolume,
2661     SimpleAudioVolume_SetMute,
2662     SimpleAudioVolume_GetMute
2663 };
2664
2665 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2666         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2667 {
2668     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2669
2670     if(!ppv)
2671         return E_POINTER;
2672     *ppv = NULL;
2673
2674     if(IsEqualIID(riid, &IID_IUnknown) ||
2675             IsEqualIID(riid, &IID_IAudioStreamVolume))
2676         *ppv = iface;
2677     if(*ppv){
2678         IUnknown_AddRef((IUnknown*)*ppv);
2679         return S_OK;
2680     }
2681
2682     WARN("Unknown interface %s\n", debugstr_guid(riid));
2683     return E_NOINTERFACE;
2684 }
2685
2686 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2687 {
2688     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2689     return IAudioClient_AddRef(&This->IAudioClient_iface);
2690 }
2691
2692 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2693 {
2694     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2695     return IAudioClient_Release(&This->IAudioClient_iface);
2696 }
2697
2698 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2699         IAudioStreamVolume *iface, UINT32 *out)
2700 {
2701     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2702
2703     TRACE("(%p)->(%p)\n", This, out);
2704
2705     if(!out)
2706         return E_POINTER;
2707
2708     *out = This->fmt->nChannels;
2709
2710     return S_OK;
2711 }
2712
2713 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2714         IAudioStreamVolume *iface, UINT32 index, float level)
2715 {
2716     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2717
2718     TRACE("(%p)->(%d, %f)\n", This, index, level);
2719
2720     if(level < 0.f || level > 1.f)
2721         return E_INVALIDARG;
2722
2723     if(index >= This->fmt->nChannels)
2724         return E_INVALIDARG;
2725
2726     TRACE("ALSA does not support volume control\n");
2727
2728     EnterCriticalSection(&This->lock);
2729
2730     This->vols[index] = level;
2731
2732     LeaveCriticalSection(&This->lock);
2733
2734     return S_OK;
2735 }
2736
2737 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2738         IAudioStreamVolume *iface, UINT32 index, float *level)
2739 {
2740     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2741
2742     TRACE("(%p)->(%d, %p)\n", This, index, level);
2743
2744     if(!level)
2745         return E_POINTER;
2746
2747     if(index >= This->fmt->nChannels)
2748         return E_INVALIDARG;
2749
2750     *level = This->vols[index];
2751
2752     return S_OK;
2753 }
2754
2755 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2756         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2757 {
2758     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2759     int i;
2760
2761     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2762
2763     if(!levels)
2764         return E_POINTER;
2765
2766     if(count != This->fmt->nChannels)
2767         return E_INVALIDARG;
2768
2769     TRACE("ALSA does not support volume control\n");
2770
2771     EnterCriticalSection(&This->lock);
2772
2773     for(i = 0; i < count; ++i)
2774         This->vols[i] = levels[i];
2775
2776     LeaveCriticalSection(&This->lock);
2777
2778     return S_OK;
2779 }
2780
2781 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2782         IAudioStreamVolume *iface, UINT32 count, float *levels)
2783 {
2784     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2785     int i;
2786
2787     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2788
2789     if(!levels)
2790         return E_POINTER;
2791
2792     if(count != This->fmt->nChannels)
2793         return E_INVALIDARG;
2794
2795     EnterCriticalSection(&This->lock);
2796
2797     for(i = 0; i < count; ++i)
2798         levels[i] = This->vols[i];
2799
2800     LeaveCriticalSection(&This->lock);
2801
2802     return S_OK;
2803 }
2804
2805 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2806 {
2807     AudioStreamVolume_QueryInterface,
2808     AudioStreamVolume_AddRef,
2809     AudioStreamVolume_Release,
2810     AudioStreamVolume_GetChannelCount,
2811     AudioStreamVolume_SetChannelVolume,
2812     AudioStreamVolume_GetChannelVolume,
2813     AudioStreamVolume_SetAllVolumes,
2814     AudioStreamVolume_GetAllVolumes
2815 };
2816
2817 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2818         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2819 {
2820     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2821
2822     if(!ppv)
2823         return E_POINTER;
2824     *ppv = NULL;
2825
2826     if(IsEqualIID(riid, &IID_IUnknown) ||
2827             IsEqualIID(riid, &IID_IChannelAudioVolume))
2828         *ppv = iface;
2829     if(*ppv){
2830         IUnknown_AddRef((IUnknown*)*ppv);
2831         return S_OK;
2832     }
2833
2834     WARN("Unknown interface %s\n", debugstr_guid(riid));
2835     return E_NOINTERFACE;
2836 }
2837
2838 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2839 {
2840     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2841     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2842 }
2843
2844 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2845 {
2846     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2847     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2848 }
2849
2850 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2851         IChannelAudioVolume *iface, UINT32 *out)
2852 {
2853     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2854     AudioSession *session = This->session;
2855
2856     TRACE("(%p)->(%p)\n", session, out);
2857
2858     if(!out)
2859         return NULL_PTR_ERR;
2860
2861     *out = session->channel_count;
2862
2863     return S_OK;
2864 }
2865
2866 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2867         IChannelAudioVolume *iface, UINT32 index, float level,
2868         const GUID *context)
2869 {
2870     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2871     AudioSession *session = This->session;
2872
2873     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2874             wine_dbgstr_guid(context));
2875
2876     if(level < 0.f || level > 1.f)
2877         return E_INVALIDARG;
2878
2879     if(index >= session->channel_count)
2880         return E_INVALIDARG;
2881
2882     if(context)
2883         FIXME("Notifications not supported yet\n");
2884
2885     TRACE("ALSA does not support volume control\n");
2886
2887     EnterCriticalSection(&session->lock);
2888
2889     session->channel_vols[index] = level;
2890
2891     LeaveCriticalSection(&session->lock);
2892
2893     return S_OK;
2894 }
2895
2896 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2897         IChannelAudioVolume *iface, UINT32 index, float *level)
2898 {
2899     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2900     AudioSession *session = This->session;
2901
2902     TRACE("(%p)->(%d, %p)\n", session, index, level);
2903
2904     if(!level)
2905         return NULL_PTR_ERR;
2906
2907     if(index >= session->channel_count)
2908         return E_INVALIDARG;
2909
2910     *level = session->channel_vols[index];
2911
2912     return S_OK;
2913 }
2914
2915 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2916         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2917         const GUID *context)
2918 {
2919     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2920     AudioSession *session = This->session;
2921     int i;
2922
2923     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2924             wine_dbgstr_guid(context));
2925
2926     if(!levels)
2927         return NULL_PTR_ERR;
2928
2929     if(count != session->channel_count)
2930         return E_INVALIDARG;
2931
2932     if(context)
2933         FIXME("Notifications not supported yet\n");
2934
2935     TRACE("ALSA does not support volume control\n");
2936
2937     EnterCriticalSection(&session->lock);
2938
2939     for(i = 0; i < count; ++i)
2940         session->channel_vols[i] = levels[i];
2941
2942     LeaveCriticalSection(&session->lock);
2943
2944     return S_OK;
2945 }
2946
2947 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2948         IChannelAudioVolume *iface, UINT32 count, float *levels)
2949 {
2950     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2951     AudioSession *session = This->session;
2952     int i;
2953
2954     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2955
2956     if(!levels)
2957         return NULL_PTR_ERR;
2958
2959     if(count != session->channel_count)
2960         return E_INVALIDARG;
2961
2962     for(i = 0; i < count; ++i)
2963         levels[i] = session->channel_vols[i];
2964
2965     return S_OK;
2966 }
2967
2968 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2969 {
2970     ChannelAudioVolume_QueryInterface,
2971     ChannelAudioVolume_AddRef,
2972     ChannelAudioVolume_Release,
2973     ChannelAudioVolume_GetChannelCount,
2974     ChannelAudioVolume_SetChannelVolume,
2975     ChannelAudioVolume_GetChannelVolume,
2976     ChannelAudioVolume_SetAllVolumes,
2977     ChannelAudioVolume_GetAllVolumes
2978 };
2979
2980 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2981         REFIID riid, void **ppv)
2982 {
2983     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2984
2985     if(!ppv)
2986         return E_POINTER;
2987     *ppv = NULL;
2988
2989     if(IsEqualIID(riid, &IID_IUnknown) ||
2990             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2991             IsEqualIID(riid, &IID_IAudioSessionManager2))
2992         *ppv = iface;
2993     if(*ppv){
2994         IUnknown_AddRef((IUnknown*)*ppv);
2995         return S_OK;
2996     }
2997
2998     WARN("Unknown interface %s\n", debugstr_guid(riid));
2999     return E_NOINTERFACE;
3000 }
3001
3002 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
3003 {
3004     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3005     ULONG ref;
3006     ref = InterlockedIncrement(&This->ref);
3007     TRACE("(%p) Refcount now %u\n", This, ref);
3008     return ref;
3009 }
3010
3011 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
3012 {
3013     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3014     ULONG ref;
3015     ref = InterlockedDecrement(&This->ref);
3016     TRACE("(%p) Refcount now %u\n", This, ref);
3017     if(!ref)
3018         HeapFree(GetProcessHeap(), 0, This);
3019     return ref;
3020 }
3021
3022 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
3023         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3024         IAudioSessionControl **out)
3025 {
3026     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3027     AudioSession *session;
3028     AudioSessionWrapper *wrapper;
3029     HRESULT hr;
3030
3031     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3032             flags, out);
3033
3034     hr = get_audio_session(session_guid, This->device, 0, &session);
3035     if(FAILED(hr))
3036         return hr;
3037
3038     wrapper = AudioSessionWrapper_Create(NULL);
3039     if(!wrapper)
3040         return E_OUTOFMEMORY;
3041
3042     wrapper->session = session;
3043
3044     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
3045
3046     return S_OK;
3047 }
3048
3049 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
3050         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
3051         ISimpleAudioVolume **out)
3052 {
3053     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3054     AudioSession *session;
3055     AudioSessionWrapper *wrapper;
3056     HRESULT hr;
3057
3058     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
3059             flags, out);
3060
3061     hr = get_audio_session(session_guid, This->device, 0, &session);
3062     if(FAILED(hr))
3063         return hr;
3064
3065     wrapper = AudioSessionWrapper_Create(NULL);
3066     if(!wrapper)
3067         return E_OUTOFMEMORY;
3068
3069     wrapper->session = session;
3070
3071     *out = &wrapper->ISimpleAudioVolume_iface;
3072
3073     return S_OK;
3074 }
3075
3076 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
3077         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
3078 {
3079     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3080     FIXME("(%p)->(%p) - stub\n", This, out);
3081     return E_NOTIMPL;
3082 }
3083
3084 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
3085         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3086 {
3087     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3088     FIXME("(%p)->(%p) - stub\n", This, notification);
3089     return E_NOTIMPL;
3090 }
3091
3092 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
3093         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
3094 {
3095     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3096     FIXME("(%p)->(%p) - stub\n", This, notification);
3097     return E_NOTIMPL;
3098 }
3099
3100 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
3101         IAudioSessionManager2 *iface, const WCHAR *session_id,
3102         IAudioVolumeDuckNotification *notification)
3103 {
3104     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3105     FIXME("(%p)->(%p) - stub\n", This, notification);
3106     return E_NOTIMPL;
3107 }
3108
3109 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
3110         IAudioSessionManager2 *iface,
3111         IAudioVolumeDuckNotification *notification)
3112 {
3113     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
3114     FIXME("(%p)->(%p) - stub\n", This, notification);
3115     return E_NOTIMPL;
3116 }
3117
3118 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
3119 {
3120     AudioSessionManager_QueryInterface,
3121     AudioSessionManager_AddRef,
3122     AudioSessionManager_Release,
3123     AudioSessionManager_GetAudioSessionControl,
3124     AudioSessionManager_GetSimpleAudioVolume,
3125     AudioSessionManager_GetSessionEnumerator,
3126     AudioSessionManager_RegisterSessionNotification,
3127     AudioSessionManager_UnregisterSessionNotification,
3128     AudioSessionManager_RegisterDuckNotification,
3129     AudioSessionManager_UnregisterDuckNotification
3130 };
3131
3132 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3133         IAudioSessionManager2 **out)
3134 {
3135     SessionMgr *This;
3136
3137     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3138     if(!This)
3139         return E_OUTOFMEMORY;
3140
3141     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3142     This->device = device;
3143     This->ref = 1;
3144
3145     *out = &This->IAudioSessionManager2_iface;
3146
3147     return S_OK;
3148 }