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