winealsa.drv: Implement volume control interfaces.
[wine] / dlls / wineoss.drv / mmdevdrv.c
1 /*
2  * Copyright 2011 Andrew Eikum for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define NONAMELESSUNION
20 #define COBJMACROS
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <math.h>
35 #include <sys/soundcard.h>
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winnls.h"
40 #include "winreg.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
44
45 #include "ole2.h"
46 #include "mmdeviceapi.h"
47 #include "devpkey.h"
48 #include "dshow.h"
49 #include "dsound.h"
50 #include "endpointvolume.h"
51
52 #include "initguid.h"
53 #include "audiopolicy.h"
54 #include "audioclient.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(oss);
57
58 #define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
59
60 static const REFERENCE_TIME DefaultPeriod = 200000;
61 static const REFERENCE_TIME MinimumPeriod = 100000;
62
63 struct ACImpl;
64 typedef struct ACImpl ACImpl;
65
66 typedef struct _AudioSession {
67     GUID guid;
68     struct list clients;
69
70     EDataFlow dataflow;
71
72     struct list entry;
73 } AudioSession;
74
75 typedef struct _AudioSessionWrapper {
76     IAudioSessionControl2 IAudioSessionControl2_iface;
77
78     LONG ref;
79
80     ACImpl *client;
81     AudioSession *session;
82 } AudioSessionWrapper;
83
84 struct ACImpl {
85     IAudioClient IAudioClient_iface;
86     IAudioRenderClient IAudioRenderClient_iface;
87     IAudioCaptureClient IAudioCaptureClient_iface;
88     ISimpleAudioVolume ISimpleAudioVolume_iface;
89     IAudioClock IAudioClock_iface;
90     IAudioClock2 IAudioClock2_iface;
91
92     LONG ref;
93
94     IMMDevice *parent;
95
96     WAVEFORMATEX *fmt;
97
98     EDataFlow dataflow;
99     DWORD flags;
100     AUDCLNT_SHAREMODE share;
101     HANDLE event;
102
103     int fd;
104     oss_audioinfo ai;
105
106     BOOL initted, playing;
107     UINT64 written_frames, held_frames, tmp_buffer_frames, inbuf_frames;
108     UINT32 period_us, bufsize_frames;
109     UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */
110
111     BYTE *local_buffer, *tmp_buffer;
112     int buf_state;
113     HANDLE timer;
114
115     CRITICAL_SECTION lock;
116
117     AudioSession *session;
118     AudioSessionWrapper *session_wrapper;
119
120     struct list entry;
121 };
122
123 enum BufferStates {
124     NOT_LOCKED = 0,
125     LOCKED_NORMAL, /* public buffer piece is from local_buffer */
126     LOCKED_WRAPPED /* public buffer piece is in tmp_buffer */
127 };
128
129 static HANDLE g_timer_q;
130
131 static CRITICAL_SECTION g_sessions_lock;
132 static struct list g_sessions = LIST_INIT(g_sessions);
133
134 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
135
136 static const IAudioClientVtbl AudioClient_Vtbl;
137 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
138 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
139 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
140 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
141 static const IAudioClockVtbl AudioClock_Vtbl;
142 static const IAudioClock2Vtbl AudioClock2_Vtbl;
143
144 static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
145 {
146     return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
147 }
148
149 static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
150 {
151     return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
152 }
153
154 static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
155 {
156     return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
157 }
158
159 static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
160 {
161     return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
162 }
163
164 static inline ACImpl *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
165 {
166     return CONTAINING_RECORD(iface, ACImpl, ISimpleAudioVolume_iface);
167 }
168
169 static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
170 {
171     return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
172 }
173
174 static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
175 {
176     return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
177 }
178
179 BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
180 {
181     if(reason == DLL_PROCESS_ATTACH){
182         g_timer_q = CreateTimerQueue();
183         if(!g_timer_q)
184             return FALSE;
185
186         InitializeCriticalSection(&g_sessions_lock);
187     }
188
189     return TRUE;
190 }
191
192 HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
193         UINT *num, UINT *def_index)
194 {
195     int i, mixer_fd;
196     oss_sysinfo sysinfo;
197     static int print_once = 0;
198
199     TRACE("%d %p %p %p\n", flow, ids, num, def_index);
200
201     mixer_fd = open("/dev/mixer", O_RDONLY, 0);
202     if(mixer_fd < 0){
203         ERR("OSS /dev/mixer doesn't seem to exist\n");
204         return AUDCLNT_E_SERVICE_NOT_RUNNING;
205     }
206
207     if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){
208         close(mixer_fd);
209
210         if(errno == EINVAL){
211             ERR("OSS version too old, need at least OSSv4\n");
212             return AUDCLNT_E_SERVICE_NOT_RUNNING;
213         }
214
215         ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno));
216         return E_FAIL;
217     }
218
219     if(!print_once){
220         TRACE("OSS sysinfo:\n");
221         TRACE("product: %s\n", sysinfo.product);
222         TRACE("version: %s\n", sysinfo.version);
223         TRACE("versionnum: %x\n", sysinfo.versionnum);
224         TRACE("numaudios: %d\n", sysinfo.numaudios);
225         TRACE("nummixers: %d\n", sysinfo.nummixers);
226         TRACE("numcards: %d\n", sysinfo.numcards);
227         TRACE("numaudioengines: %d\n", sysinfo.numaudioengines);
228         print_once = 1;
229     }
230
231     if(sysinfo.numaudios <= 0){
232         WARN("No audio devices!\n");
233         close(mixer_fd);
234         return AUDCLNT_E_SERVICE_NOT_RUNNING;
235     }
236
237     *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *));
238     *keys = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(char *));
239
240     *num = 0;
241     *def_index = -1;
242     for(i = 0; i < sysinfo.numaudios; ++i){
243         oss_audioinfo ai = {0};
244
245         ai.dev = i;
246         if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){
247             WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno,
248                     strerror(errno));
249             continue;
250         }
251
252         if((flow == eCapture && (ai.caps & PCM_CAP_INPUT)) ||
253                 (flow == eRender && (ai.caps & PCM_CAP_OUTPUT))){
254             size_t len;
255
256             (*keys)[*num] = HeapAlloc(GetProcessHeap(), 0,
257                     strlen(ai.devnode) + 1);
258             if(!(*keys)[*num]){
259                 for(i = 0; i < *num; ++i){
260                     HeapFree(GetProcessHeap(), 0, (*ids)[i]);
261                     HeapFree(GetProcessHeap(), 0, (*keys)[i]);
262                 }
263                 HeapFree(GetProcessHeap(), 0, *ids);
264                 HeapFree(GetProcessHeap(), 0, *keys);
265                 close(mixer_fd);
266                 return E_OUTOFMEMORY;
267             }
268             strcpy((*keys)[*num], ai.devnode);
269
270             len = MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, NULL, 0);
271             (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0,
272                     len * sizeof(WCHAR));
273             if(!(*ids)[*num]){
274                 HeapFree(GetProcessHeap(), 0, (*keys)[*num]);
275                 for(i = 0; i < *num; ++i){
276                     HeapFree(GetProcessHeap(), 0, (*ids)[i]);
277                     HeapFree(GetProcessHeap(), 0, (*keys)[i]);
278                 }
279                 HeapFree(GetProcessHeap(), 0, *ids);
280                 HeapFree(GetProcessHeap(), 0, *keys);
281                 close(mixer_fd);
282                 return E_OUTOFMEMORY;
283             }
284             MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1,
285                     (*ids)[*num], len);
286
287             if(ai.caps & PCM_CAP_DEFAULT)
288                 *def_index = *num;
289
290             (*num)++;
291         }
292     }
293
294     if(*def_index == -1)
295         *def_index = 0;
296
297     close(mixer_fd);
298
299     return S_OK;
300 }
301
302 HRESULT WINAPI AUDDRV_GetAudioEndpoint(char *devnode, IMMDevice *dev,
303         EDataFlow dataflow, IAudioClient **out)
304 {
305     ACImpl *This;
306
307     TRACE("%s %p %d %p\n", devnode, dev, dataflow, out);
308
309     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
310     if(!This)
311         return E_OUTOFMEMORY;
312
313     if(dataflow == eRender)
314         This->fd = open(devnode, O_WRONLY, 0);
315     else if(dataflow == eCapture)
316         This->fd = open(devnode, O_RDONLY, 0);
317     else{
318         HeapFree(GetProcessHeap(), 0, This);
319         return E_INVALIDARG;
320     }
321     if(This->fd < 0){
322         ERR("Unable to open device %s: %d (%s)\n", devnode, errno,
323                 strerror(errno));
324         HeapFree(GetProcessHeap(), 0, This);
325         return AUDCLNT_E_DEVICE_INVALIDATED;
326     }
327
328     This->dataflow = dataflow;
329
330     This->ai.dev = -1;
331     if(ioctl(This->fd, SNDCTL_ENGINEINFO, &This->ai) < 0){
332         ERR("Unable to get audio info for device %s: %d (%s)\n", devnode,
333                 errno, strerror(errno));
334         close(This->fd);
335         HeapFree(GetProcessHeap(), 0, This);
336         return E_FAIL;
337     }
338
339     TRACE("OSS audioinfo:\n");
340     TRACE("devnode: %s\n", This->ai.devnode);
341     TRACE("name: %s\n", This->ai.name);
342     TRACE("busy: %x\n", This->ai.busy);
343     TRACE("caps: %x\n", This->ai.caps);
344     TRACE("iformats: %x\n", This->ai.iformats);
345     TRACE("oformats: %x\n", This->ai.oformats);
346     TRACE("enabled: %d\n", This->ai.enabled);
347     TRACE("min_rate: %d\n", This->ai.min_rate);
348     TRACE("max_rate: %d\n", This->ai.max_rate);
349     TRACE("min_channels: %d\n", This->ai.min_channels);
350     TRACE("max_channels: %d\n", This->ai.max_channels);
351
352     This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
353     This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
354     This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
355     This->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
356     This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
357     This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
358
359     InitializeCriticalSection(&This->lock);
360
361     This->parent = dev;
362     IMMDevice_AddRef(This->parent);
363
364     IAudioClient_AddRef(&This->IAudioClient_iface);
365
366     *out = &This->IAudioClient_iface;
367
368     return S_OK;
369 }
370
371 static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
372         REFIID riid, void **ppv)
373 {
374     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
375
376     if(!ppv)
377         return E_POINTER;
378     *ppv = NULL;
379     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
380         *ppv = iface;
381     if(*ppv){
382         IUnknown_AddRef((IUnknown*)*ppv);
383         return S_OK;
384     }
385     WARN("Unknown interface %s\n", debugstr_guid(riid));
386     return E_NOINTERFACE;
387 }
388
389 static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface)
390 {
391     ACImpl *This = impl_from_IAudioClient(iface);
392     ULONG ref;
393     ref = InterlockedIncrement(&This->ref);
394     TRACE("(%p) Refcount now %u\n", This, ref);
395     return ref;
396 }
397
398 static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
399 {
400     ACImpl *This = impl_from_IAudioClient(iface);
401     ULONG ref;
402     ref = InterlockedDecrement(&This->ref);
403     TRACE("(%p) Refcount now %u\n", This, ref);
404     if(!ref){
405         IAudioClient_Stop(iface);
406         IMMDevice_Release(This->parent);
407         DeleteCriticalSection(&This->lock);
408         close(This->fd);
409         if(This->initted){
410             EnterCriticalSection(&g_sessions_lock);
411             list_remove(&This->entry);
412             if(list_empty(&This->session->clients)){
413                 list_remove(&This->session->entry);
414                 HeapFree(GetProcessHeap(), 0, This->session);
415             }
416             LeaveCriticalSection(&g_sessions_lock);
417         }
418         HeapFree(GetProcessHeap(), 0, This->local_buffer);
419         HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
420         CoTaskMemFree(This->fmt);
421         HeapFree(GetProcessHeap(), 0, This);
422     }
423     return ref;
424 }
425
426 static void dump_fmt(const WAVEFORMATEX *fmt)
427 {
428     TRACE("wFormatTag: 0x%x (", fmt->wFormatTag);
429     switch(fmt->wFormatTag){
430     case WAVE_FORMAT_PCM:
431         TRACE("WAVE_FORMAT_PCM");
432         break;
433     case WAVE_FORMAT_IEEE_FLOAT:
434         TRACE("WAVE_FORMAT_IEEE_FLOAT");
435         break;
436     case WAVE_FORMAT_EXTENSIBLE:
437         TRACE("WAVE_FORMAT_EXTENSIBLE");
438         break;
439     default:
440         TRACE("Unknown");
441         break;
442     }
443     TRACE(")\n");
444
445     TRACE("nChannels: %u\n", fmt->nChannels);
446     TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec);
447     TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec);
448     TRACE("nBlockAlign: %u\n", fmt->nBlockAlign);
449     TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample);
450     TRACE("cbSize: %u\n", fmt->cbSize);
451
452     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
453         WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
454         TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask);
455         TRACE("Samples: %04x\n", fmtex->Samples.wReserved);
456         TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat));
457     }
458 }
459
460 static DWORD get_channel_mask(unsigned int channels)
461 {
462     switch(channels){
463     case 0:
464         return 0;
465     case 1:
466         return SPEAKER_FRONT_CENTER;
467     case 2:
468         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
469     case 3:
470         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
471             SPEAKER_LOW_FREQUENCY;
472     case 4:
473         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
474             SPEAKER_BACK_RIGHT;
475     case 5:
476         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
477             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
478     case 6:
479         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
480             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
481     case 7:
482         return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
483             SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
484             SPEAKER_BACK_CENTER;
485     }
486     FIXME("Unknown speaker configuration: %u\n", channels);
487     return 0;
488 }
489
490 static int get_oss_format(const WAVEFORMATEX *fmt)
491 {
492     WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt;
493
494     if(fmt->wFormatTag == WAVE_FORMAT_PCM ||
495             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
496              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){
497         switch(fmt->wBitsPerSample){
498         case 8:
499             return AFMT_U8;
500         case 16:
501             return AFMT_S16_LE;
502         case 24:
503             return AFMT_S24_PACKED;
504         case 32:
505             return AFMT_S32_LE;
506         }
507         return -1;
508     }
509
510     if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
511             (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
512              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
513         if(fmt->wBitsPerSample != 32)
514             return -1;
515
516         return AFMT_FLOAT;
517     }
518
519     return -1;
520 }
521
522 static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
523 {
524     WAVEFORMATEX *ret;
525     size_t size;
526
527     if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
528         size = sizeof(WAVEFORMATEXTENSIBLE);
529     else
530         size = sizeof(WAVEFORMATEX);
531
532     ret = CoTaskMemAlloc(size);
533     if(!ret)
534         return NULL;
535
536     memcpy(ret, fmt, size);
537
538     ret->cbSize = size - sizeof(WAVEFORMATEX);
539
540     return ret;
541 }
542
543 static HRESULT setup_oss_device(ACImpl *This, const WAVEFORMATEX *fmt,
544         WAVEFORMATEX **out)
545 {
546     int tmp, oss_format;
547     double tenth;
548     HRESULT ret = S_OK;
549     WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt;
550     WAVEFORMATEX *closest = NULL;
551
552     tmp = oss_format = get_oss_format(fmt);
553     if(oss_format < 0)
554         return AUDCLNT_E_UNSUPPORTED_FORMAT;
555     if(ioctl(This->fd, SNDCTL_DSP_SETFMT, &tmp) < 0){
556         WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno));
557         return E_FAIL;
558     }
559     if(tmp != oss_format){
560         TRACE("Format unsupported by this OSS version: %x\n", oss_format);
561         return AUDCLNT_E_UNSUPPORTED_FORMAT;
562     }
563
564     closest = clone_format(fmt);
565
566     tmp = fmt->nSamplesPerSec;
567     if(ioctl(This->fd, SNDCTL_DSP_SPEED, &tmp) < 0){
568         WARN("SPEED failed: %d (%s)\n", errno, strerror(errno));
569         CoTaskMemFree(closest);
570         return E_FAIL;
571     }
572     tenth = fmt->nSamplesPerSec * 0.1;
573     if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){
574         ret = S_FALSE;
575         closest->nSamplesPerSec = tmp;
576     }
577
578     tmp = fmt->nChannels;
579     if(ioctl(This->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){
580         WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno));
581         CoTaskMemFree(closest);
582         return E_FAIL;
583     }
584     if(tmp != fmt->nChannels){
585         ret = S_FALSE;
586         closest->nChannels = tmp;
587     }
588
589     if(closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE){
590         DWORD mask = get_channel_mask(closest->nChannels);
591
592         ((WAVEFORMATEXTENSIBLE*)closest)->dwChannelMask = mask;
593
594         if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
595                 fmtex->dwChannelMask != mask)
596             ret = S_FALSE;
597     }
598
599     if(ret == S_OK || !out){
600         CoTaskMemFree( closest);
601         if(out)
602             *out = NULL;
603     }else{
604         closest->nBlockAlign =
605             closest->nChannels * closest->wBitsPerSample / 8;
606         closest->nAvgBytesPerSec =
607             closest->nBlockAlign * closest->nSamplesPerSec;
608         *out = closest;
609     }
610
611     TRACE("returning: %08x\n", ret);
612     return ret;
613 }
614
615 static AudioSession *create_session(const GUID *guid, EDataFlow flow)
616 {
617     AudioSession *ret;
618
619     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
620     if(!ret)
621         return NULL;
622
623     memcpy(&ret->guid, guid, sizeof(GUID));
624
625     ret->dataflow = flow;
626
627     list_init(&ret->clients);
628
629     list_add_head(&g_sessions, &ret->entry);
630
631     return ret;
632 }
633
634 static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
635         AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration,
636         REFERENCE_TIME period, const WAVEFORMATEX *fmt,
637         const GUID *sessionguid)
638 {
639     ACImpl *This = impl_from_IAudioClient(iface);
640     int mask;
641     HRESULT hr;
642
643     TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
644           wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
645
646     if(!fmt)
647         return E_POINTER;
648
649     dump_fmt(fmt);
650
651     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
652         return AUDCLNT_E_NOT_INITIALIZED;
653
654     if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
655                 AUDCLNT_STREAMFLAGS_LOOPBACK |
656                 AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
657                 AUDCLNT_STREAMFLAGS_NOPERSIST |
658                 AUDCLNT_STREAMFLAGS_RATEADJUST |
659                 AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED |
660                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE |
661                 AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED)){
662         TRACE("Unknown flags: %08x\n", flags);
663         return E_INVALIDARG;
664     }
665
666     EnterCriticalSection(&This->lock);
667
668     if(This->initted){
669         LeaveCriticalSection(&This->lock);
670         return AUDCLNT_E_ALREADY_INITIALIZED;
671     }
672
673     hr = setup_oss_device(This, fmt, NULL);
674     if(hr == S_FALSE){
675         LeaveCriticalSection(&This->lock);
676         return AUDCLNT_E_UNSUPPORTED_FORMAT;
677     }
678     if(FAILED(hr)){
679         LeaveCriticalSection(&This->lock);
680         return hr;
681     }
682
683     mask = 0;
684     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
685         LeaveCriticalSection(&This->lock);
686         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
687         return E_FAIL;
688     }
689
690     mask = (100 << 8) | 100;
691     if(ioctl(This->fd, SNDCTL_DSP_SETPLAYVOL, &mask) < 0)
692         WARN("SETPLAYVOL failed: %d (%s)\n", errno, strerror(errno));
693
694     This->fmt = clone_format(fmt);
695     if(!This->fmt){
696         LeaveCriticalSection(&This->lock);
697         return E_OUTOFMEMORY;
698     }
699
700     if(period)
701         This->period_us = period / 10;
702     else
703         This->period_us = DefaultPeriod / 10;
704
705     This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
706     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
707             This->bufsize_frames * fmt->nBlockAlign);
708     if(!This->local_buffer){
709         CoTaskMemFree(This->fmt);
710         This->fmt = NULL;
711         LeaveCriticalSection(&This->lock);
712         return E_OUTOFMEMORY;
713     }
714
715     This->share = mode;
716     This->flags = flags;
717
718     EnterCriticalSection(&g_sessions_lock);
719
720     if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){
721         This->session = create_session(&GUID_NULL, This->dataflow);
722         if(!This->session){
723             CoTaskMemFree(This->fmt);
724             This->fmt = NULL;
725             LeaveCriticalSection(&g_sessions_lock);
726             return E_OUTOFMEMORY;
727         }
728     }else{
729         AudioSession *session;
730
731         LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry)
732             if(IsEqualGUID(sessionguid, &session->guid) &&
733                     This->dataflow == session->dataflow)
734                 This->session = session;
735
736         if(!This->session){
737             This->session = create_session(sessionguid, This->dataflow);
738             if(!This->session){
739                 CoTaskMemFree(This->fmt);
740                 This->fmt = NULL;
741                 LeaveCriticalSection(&g_sessions_lock);
742                 return E_OUTOFMEMORY;
743             }
744         }
745     }
746
747     list_add_tail(&This->session->clients, &This->entry);
748
749     LeaveCriticalSection(&g_sessions_lock);
750
751     This->initted = TRUE;
752
753     LeaveCriticalSection(&This->lock);
754
755     return S_OK;
756 }
757
758 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
759         UINT32 *frames)
760 {
761     ACImpl *This = impl_from_IAudioClient(iface);
762
763     TRACE("(%p)->(%p)\n", This, frames);
764
765     if(!frames)
766         return E_POINTER;
767
768     EnterCriticalSection(&This->lock);
769
770     if(!This->initted){
771         LeaveCriticalSection(&This->lock);
772         return AUDCLNT_E_NOT_INITIALIZED;
773     }
774
775     *frames = This->bufsize_frames;
776
777     LeaveCriticalSection(&This->lock);
778
779     return S_OK;
780 }
781
782 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
783         REFERENCE_TIME *latency)
784 {
785     ACImpl *This = impl_from_IAudioClient(iface);
786
787     TRACE("(%p)->(%p)\n", This, latency);
788
789     if(!latency)
790         return E_POINTER;
791
792     EnterCriticalSection(&This->lock);
793
794     if(!This->initted){
795         LeaveCriticalSection(&This->lock);
796         return AUDCLNT_E_NOT_INITIALIZED;
797     }
798
799     if(This->dataflow == eRender){
800         int delay_bytes;
801         double delay_s;
802
803         if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
804             LeaveCriticalSection(&This->lock);
805             WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
806             return E_FAIL;
807         }
808
809         delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
810                 This->fmt->nBlockAlign);
811
812         *latency = delay_s * 10000000;
813     }else
814         *latency = 10000; /* OSS doesn't provide input latency */
815
816     LeaveCriticalSection(&This->lock);
817
818     return S_OK;
819 }
820
821 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
822         UINT32 *numpad)
823 {
824     ACImpl *This = impl_from_IAudioClient(iface);
825     audio_buf_info bi;
826
827     TRACE("(%p)->(%p)\n", This, numpad);
828
829     if(!numpad)
830         return E_POINTER;
831
832     EnterCriticalSection(&This->lock);
833
834     if(!This->initted){
835         LeaveCriticalSection(&This->lock);
836         return AUDCLNT_E_NOT_INITIALIZED;
837     }
838
839     if(This->dataflow == eRender){
840         if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
841             LeaveCriticalSection(&This->lock);
842             WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
843             return E_FAIL;
844         }
845
846         *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
847             This->fmt->nBlockAlign;
848
849         /* when the OSS buffer has less than one fragment of data, including
850          * no data, it often reports it as some non-zero portion of a
851          * fragment. when it has more than one fragment of data, it reports
852          * it as some multiple of that portion of the fragment size.
853          *
854          * so, we have to do some ugly workarounds to report the timing
855          * as accurately as possible */
856         if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
857             *numpad = This->inbuf_frames;
858             This->inbuf_frames = 0;
859         }else{
860             if(*numpad < This->inbuf_frames)
861                 This->inbuf_frames = *numpad;
862             else
863                 *numpad = This->inbuf_frames;
864         }
865     }else if(This->dataflow == eCapture){
866         if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
867             LeaveCriticalSection(&This->lock);
868             WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
869             return E_FAIL;
870         }
871
872         if(bi.bytes <= bi.fragsize)
873             *numpad = 0;
874         else
875             *numpad = bi.bytes / This->fmt->nBlockAlign;
876     }else{
877         LeaveCriticalSection(&This->lock);
878         return E_UNEXPECTED;
879     }
880
881     *numpad += This->held_frames;
882
883     LeaveCriticalSection(&This->lock);
884
885     return S_OK;
886 }
887
888 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
889         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
890         WAVEFORMATEX **outpwfx)
891 {
892     ACImpl *This = impl_from_IAudioClient(iface);
893     HRESULT ret;
894
895     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
896
897     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
898         return E_POINTER;
899
900     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
901         return E_INVALIDARG;
902
903     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
904             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
905         return E_INVALIDARG;
906
907     dump_fmt(pwfx);
908
909     EnterCriticalSection(&This->lock);
910
911     ret = setup_oss_device(This, pwfx, outpwfx);
912
913     LeaveCriticalSection(&This->lock);
914
915     return ret;
916 }
917
918 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
919         WAVEFORMATEX **pwfx)
920 {
921     ACImpl *This = impl_from_IAudioClient(iface);
922     WAVEFORMATEXTENSIBLE *fmt;
923     int formats;
924
925     TRACE("(%p)->(%p)\n", This, pwfx);
926
927     if(!pwfx)
928         return E_POINTER;
929
930     *pwfx = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
931     if(!*pwfx)
932         return E_OUTOFMEMORY;
933
934     fmt = (WAVEFORMATEXTENSIBLE*)*pwfx;
935
936     if(This->dataflow == eRender)
937         formats = This->ai.oformats;
938     else if(This->dataflow == eCapture)
939         formats = This->ai.iformats;
940     else
941         return E_UNEXPECTED;
942
943     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
944     if(formats & AFMT_S16_LE){
945         fmt->Format.wBitsPerSample = 16;
946         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
947     }else if(formats & AFMT_FLOAT){
948         fmt->Format.wBitsPerSample = 32;
949         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
950     }else if(formats & AFMT_U8){
951         fmt->Format.wBitsPerSample = 8;
952         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
953     }else if(formats & AFMT_S32_LE){
954         fmt->Format.wBitsPerSample = 32;
955         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
956     }else if(formats & AFMT_S24_PACKED){
957         fmt->Format.wBitsPerSample = 24;
958         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
959     }else{
960         ERR("Didn't recognize any available OSS formats: %x\n", formats);
961         return E_FAIL;
962     }
963
964     fmt->Format.nChannels = This->ai.max_channels;
965     fmt->Format.nSamplesPerSec = This->ai.max_rate;
966     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
967
968     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
969             fmt->Format.nChannels) / 8;
970     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
971         fmt->Format.nBlockAlign;
972
973     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
974     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
975
976     dump_fmt(*pwfx);
977
978     return S_OK;
979 }
980
981 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
982         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
983 {
984     ACImpl *This = impl_from_IAudioClient(iface);
985
986     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
987
988     if(!defperiod && !minperiod)
989         return E_POINTER;
990
991     EnterCriticalSection(&This->lock);
992
993     if(defperiod)
994         *defperiod = DefaultPeriod;
995     if(minperiod)
996         *minperiod = MinimumPeriod;
997
998     LeaveCriticalSection(&This->lock);
999
1000     return S_OK;
1001 }
1002
1003 static void oss_write_data(ACImpl *This)
1004 {
1005     ssize_t written;
1006     UINT32 written_frames;
1007     size_t to_write;
1008     BYTE *buf =
1009         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1010
1011     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1012         to_write = This->bufsize_frames - This->lcl_offs_frames;
1013     else
1014         to_write = This->held_frames;
1015
1016     written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1017     if(written < 0){
1018         WARN("write failed: %d (%s)\n", errno, strerror(errno));
1019         return;
1020     }
1021     written_frames = written / This->fmt->nBlockAlign;
1022
1023     This->lcl_offs_frames += written_frames;
1024     This->lcl_offs_frames %= This->bufsize_frames;
1025     This->held_frames -= written_frames;
1026     This->inbuf_frames += written_frames;
1027
1028     if(written_frames < to_write){
1029         /* OSS buffer probably full */
1030         return;
1031     }
1032
1033     if(This->held_frames){
1034         /* wrapped and have some data back at the start to write */
1035         written = write(This->fd, This->local_buffer,
1036                 This->held_frames * This->fmt->nBlockAlign);
1037         if(written < 0){
1038             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1039             return;
1040         }
1041         written_frames = written / This->fmt->nBlockAlign;
1042
1043         This->lcl_offs_frames += written_frames;
1044         This->lcl_offs_frames %= This->bufsize_frames;
1045         This->held_frames -= written_frames;
1046         This->inbuf_frames += written_frames;
1047     }
1048 }
1049
1050 static void oss_read_data(ACImpl *This)
1051 {
1052     UINT64 pos, readable;
1053     audio_buf_info bi;
1054     ssize_t nread;
1055
1056     if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1057         WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1058         return;
1059     }
1060
1061     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1062     readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1063
1064     if(bi.bytes < readable)
1065         readable = bi.bytes;
1066
1067     nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1068             readable);
1069     if(nread < 0){
1070         WARN("read failed: %d (%s)\n", errno, strerror(errno));
1071         return;
1072     }
1073
1074     This->held_frames += nread / This->fmt->nBlockAlign;
1075
1076     if(This->held_frames > This->bufsize_frames){
1077         WARN("Overflow of unread data\n");
1078         This->lcl_offs_frames += This->held_frames;
1079         This->lcl_offs_frames %= This->bufsize_frames;
1080         This->held_frames = This->bufsize_frames;
1081     }
1082 }
1083
1084 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1085 {
1086     ACImpl *This = user;
1087
1088     EnterCriticalSection(&This->lock);
1089
1090     if(This->dataflow == eRender)
1091         oss_write_data(This);
1092     else if(This->dataflow == eCapture)
1093         oss_read_data(This);
1094
1095     if(This->event)
1096         SetEvent(This->event);
1097
1098     LeaveCriticalSection(&This->lock);
1099 }
1100
1101 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1102 {
1103     ACImpl *This = impl_from_IAudioClient(iface);
1104     int mask;
1105
1106     TRACE("(%p)\n", This);
1107
1108     EnterCriticalSection(&This->lock);
1109
1110     if(!This->initted){
1111         LeaveCriticalSection(&This->lock);
1112         return AUDCLNT_E_NOT_INITIALIZED;
1113     }
1114
1115     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1116         LeaveCriticalSection(&This->lock);
1117         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1118     }
1119
1120     if(This->playing){
1121         LeaveCriticalSection(&This->lock);
1122         return AUDCLNT_E_NOT_STOPPED;
1123     }
1124
1125     if(This->dataflow == eRender)
1126         mask = PCM_ENABLE_OUTPUT;
1127     else if(This->dataflow == eCapture)
1128         mask = PCM_ENABLE_INPUT;
1129     else{
1130         LeaveCriticalSection(&This->lock);
1131         return E_UNEXPECTED;
1132     }
1133
1134     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1135         LeaveCriticalSection(&This->lock);
1136         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1137         return E_FAIL;
1138     }
1139
1140     if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1141                 oss_period_callback, This, 0, This->period_us / 1000,
1142                 WT_EXECUTEINTIMERTHREAD))
1143         ERR("Unable to create period timer: %u\n", GetLastError());
1144
1145     This->playing = TRUE;
1146
1147     LeaveCriticalSection(&This->lock);
1148
1149     return S_OK;
1150 }
1151
1152 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1153 {
1154     ACImpl *This = impl_from_IAudioClient(iface);
1155     int mask;
1156
1157     TRACE("(%p)\n", This);
1158
1159     EnterCriticalSection(&This->lock);
1160
1161     if(!This->initted){
1162         LeaveCriticalSection(&This->lock);
1163         return AUDCLNT_E_NOT_INITIALIZED;
1164     }
1165
1166     if(!This->playing){
1167         LeaveCriticalSection(&This->lock);
1168         return S_FALSE;
1169     }
1170
1171     if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1172         DeleteTimerQueueTimer(g_timer_q, This->timer,
1173                 INVALID_HANDLE_VALUE);
1174         This->timer = NULL;
1175     }
1176
1177     if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1178         LeaveCriticalSection(&This->lock);
1179         WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1180         return E_FAIL;
1181     }
1182
1183     mask = 0;
1184     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1185         LeaveCriticalSection(&This->lock);
1186         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1187         return E_FAIL;
1188     }
1189
1190     This->playing = FALSE;
1191
1192     LeaveCriticalSection(&This->lock);
1193
1194     return S_OK;
1195 }
1196
1197 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1198 {
1199     ACImpl *This = impl_from_IAudioClient(iface);
1200
1201     TRACE("(%p)\n", This);
1202
1203     EnterCriticalSection(&This->lock);
1204
1205     if(!This->initted){
1206         LeaveCriticalSection(&This->lock);
1207         return AUDCLNT_E_NOT_INITIALIZED;
1208     }
1209
1210     if(This->playing){
1211         LeaveCriticalSection(&This->lock);
1212         return AUDCLNT_E_NOT_STOPPED;
1213     }
1214
1215     This->written_frames = 0;
1216     This->inbuf_frames = 0;
1217     This->held_frames = 0;
1218
1219     if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1220         WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1221
1222     LeaveCriticalSection(&This->lock);
1223
1224     return S_OK;
1225 }
1226
1227 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1228         HANDLE event)
1229 {
1230     ACImpl *This = impl_from_IAudioClient(iface);
1231
1232     TRACE("(%p)->(%p)\n", This, event);
1233
1234     if(!event)
1235         return E_INVALIDARG;
1236
1237     EnterCriticalSection(&This->lock);
1238
1239     if(!This->initted){
1240         LeaveCriticalSection(&This->lock);
1241         return AUDCLNT_E_NOT_INITIALIZED;
1242     }
1243
1244     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1245         LeaveCriticalSection(&This->lock);
1246         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1247     }
1248
1249     This->event = event;
1250
1251     LeaveCriticalSection(&This->lock);
1252
1253     return S_OK;
1254 }
1255
1256 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1257         void **ppv)
1258 {
1259     ACImpl *This = impl_from_IAudioClient(iface);
1260
1261     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1262
1263     if(!ppv)
1264         return E_POINTER;
1265     *ppv = NULL;
1266
1267     EnterCriticalSection(&This->lock);
1268
1269     if(!This->initted){
1270         LeaveCriticalSection(&This->lock);
1271         return AUDCLNT_E_NOT_INITIALIZED;
1272     }
1273
1274     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1275         if(This->dataflow != eRender){
1276             LeaveCriticalSection(&This->lock);
1277             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1278         }
1279         *ppv = &This->IAudioRenderClient_iface;
1280     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1281         if(This->dataflow != eCapture){
1282             LeaveCriticalSection(&This->lock);
1283             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1284         }
1285         *ppv = &This->IAudioCaptureClient_iface;
1286     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1287         if(!This->session_wrapper){
1288             This->session_wrapper = AudioSessionWrapper_Create(This);
1289             if(!This->session_wrapper){
1290                 LeaveCriticalSection(&This->lock);
1291                 return E_OUTOFMEMORY;
1292             }
1293         }
1294
1295         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1296     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1297         *ppv = &This->ISimpleAudioVolume_iface;
1298     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1299         *ppv = &This->IAudioClock_iface;
1300     }
1301
1302     if(*ppv){
1303         IUnknown_AddRef((IUnknown*)*ppv);
1304         LeaveCriticalSection(&This->lock);
1305         return S_OK;
1306     }
1307
1308     LeaveCriticalSection(&This->lock);
1309
1310     FIXME("stub %s\n", debugstr_guid(riid));
1311     return E_NOINTERFACE;
1312 }
1313
1314 static const IAudioClientVtbl AudioClient_Vtbl =
1315 {
1316     AudioClient_QueryInterface,
1317     AudioClient_AddRef,
1318     AudioClient_Release,
1319     AudioClient_Initialize,
1320     AudioClient_GetBufferSize,
1321     AudioClient_GetStreamLatency,
1322     AudioClient_GetCurrentPadding,
1323     AudioClient_IsFormatSupported,
1324     AudioClient_GetMixFormat,
1325     AudioClient_GetDevicePeriod,
1326     AudioClient_Start,
1327     AudioClient_Stop,
1328     AudioClient_Reset,
1329     AudioClient_SetEventHandle,
1330     AudioClient_GetService
1331 };
1332
1333 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1334         IAudioRenderClient *iface, REFIID riid, void **ppv)
1335 {
1336     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1337
1338     if(!ppv)
1339         return E_POINTER;
1340     *ppv = NULL;
1341
1342     if(IsEqualIID(riid, &IID_IUnknown) ||
1343             IsEqualIID(riid, &IID_IAudioRenderClient))
1344         *ppv = iface;
1345     if(*ppv){
1346         IUnknown_AddRef((IUnknown*)*ppv);
1347         return S_OK;
1348     }
1349
1350     WARN("Unknown interface %s\n", debugstr_guid(riid));
1351     return E_NOINTERFACE;
1352 }
1353
1354 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1355 {
1356     ACImpl *This = impl_from_IAudioRenderClient(iface);
1357     return AudioClient_AddRef(&This->IAudioClient_iface);
1358 }
1359
1360 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1361 {
1362     ACImpl *This = impl_from_IAudioRenderClient(iface);
1363     return AudioClient_Release(&This->IAudioClient_iface);
1364 }
1365
1366 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1367         UINT32 frames, BYTE **data)
1368 {
1369     ACImpl *This = impl_from_IAudioRenderClient(iface);
1370     UINT32 pad, write_pos;
1371     HRESULT hr;
1372
1373     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1374
1375     if(!data)
1376         return E_POINTER;
1377
1378     EnterCriticalSection(&This->lock);
1379
1380     if(This->buf_state != NOT_LOCKED){
1381         LeaveCriticalSection(&This->lock);
1382         return AUDCLNT_E_OUT_OF_ORDER;
1383     }
1384
1385     if(!frames){
1386         This->buf_state = LOCKED_NORMAL;
1387         LeaveCriticalSection(&This->lock);
1388         return S_OK;
1389     }
1390
1391     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1392     if(FAILED(hr)){
1393         LeaveCriticalSection(&This->lock);
1394         return hr;
1395     }
1396
1397     if(pad + frames > This->bufsize_frames){
1398         LeaveCriticalSection(&This->lock);
1399         return AUDCLNT_E_BUFFER_TOO_LARGE;
1400     }
1401
1402     write_pos =
1403         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1404     if(write_pos + frames > This->bufsize_frames){
1405         if(This->tmp_buffer_frames < frames){
1406             if(This->tmp_buffer)
1407                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1408                         This->tmp_buffer, frames * This->fmt->nBlockAlign);
1409             else
1410                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1411                         frames * This->fmt->nBlockAlign);
1412             if(!This->tmp_buffer){
1413                 LeaveCriticalSection(&This->lock);
1414                 return E_OUTOFMEMORY;
1415             }
1416             This->tmp_buffer_frames = frames;
1417         }
1418         *data = This->tmp_buffer;
1419         This->buf_state = LOCKED_WRAPPED;
1420     }else{
1421         *data = This->local_buffer +
1422             This->lcl_offs_frames * This->fmt->nBlockAlign;
1423         This->buf_state = LOCKED_NORMAL;
1424     }
1425
1426     LeaveCriticalSection(&This->lock);
1427
1428     return S_OK;
1429 }
1430
1431 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1432 {
1433     UINT32 write_offs_frames =
1434         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1435     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1436     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1437     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1438
1439     if(written_bytes < chunk_bytes){
1440         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1441     }else{
1442         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1443         memcpy(This->local_buffer, buffer + chunk_bytes,
1444                 written_bytes - chunk_bytes);
1445     }
1446 }
1447
1448 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1449         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1450 {
1451     ACImpl *This = impl_from_IAudioRenderClient(iface);
1452     BYTE *buffer;
1453     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1454
1455     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1456
1457     EnterCriticalSection(&This->lock);
1458
1459     if(This->buf_state == NOT_LOCKED || !written_frames){
1460         This->buf_state = NOT_LOCKED;
1461         LeaveCriticalSection(&This->lock);
1462         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1463     }
1464
1465     if(This->buf_state == LOCKED_NORMAL)
1466         buffer = This->local_buffer +
1467             This->lcl_offs_frames * This->fmt->nBlockAlign;
1468     else
1469         buffer = This->tmp_buffer;
1470
1471     if(flags & AUDCLNT_BUFFERFLAGS_SILENT){
1472         WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1473         if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1474                 (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1475                  IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1476                 This->fmt->wBitsPerSample == 8)
1477             memset(buffer, 128, written_frames * This->fmt->nBlockAlign);
1478         else
1479             memset(buffer, 0, written_frames * This->fmt->nBlockAlign);
1480     }
1481
1482     if(This->held_frames){
1483         if(This->buf_state == LOCKED_WRAPPED)
1484             oss_wrap_buffer(This, buffer, written_bytes);
1485
1486         This->held_frames += written_frames;
1487     }else{
1488         ssize_t w_bytes;
1489         UINT32 w_frames;
1490
1491         w_bytes = write(This->fd, buffer,
1492                 written_frames * This->fmt->nBlockAlign);
1493         if(w_bytes < 0){
1494             LeaveCriticalSection(&This->lock);
1495             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1496             return E_FAIL;
1497         }
1498         w_frames = w_bytes / This->fmt->nBlockAlign;
1499         This->inbuf_frames += w_frames;
1500
1501         if(w_frames < written_frames){
1502             if(This->buf_state == LOCKED_WRAPPED)
1503                 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1504                         written_frames - w_frames);
1505
1506             This->held_frames = written_frames - w_frames;
1507         }
1508     }
1509
1510     This->written_frames += written_frames;
1511     This->buf_state = NOT_LOCKED;
1512
1513     LeaveCriticalSection(&This->lock);
1514
1515     return S_OK;
1516 }
1517
1518 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1519     AudioRenderClient_QueryInterface,
1520     AudioRenderClient_AddRef,
1521     AudioRenderClient_Release,
1522     AudioRenderClient_GetBuffer,
1523     AudioRenderClient_ReleaseBuffer
1524 };
1525
1526 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1527         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1528 {
1529     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1530
1531     if(!ppv)
1532         return E_POINTER;
1533     *ppv = NULL;
1534
1535     if(IsEqualIID(riid, &IID_IUnknown) ||
1536             IsEqualIID(riid, &IID_IAudioCaptureClient))
1537         *ppv = iface;
1538     if(*ppv){
1539         IUnknown_AddRef((IUnknown*)*ppv);
1540         return S_OK;
1541     }
1542
1543     WARN("Unknown interface %s\n", debugstr_guid(riid));
1544     return E_NOINTERFACE;
1545 }
1546
1547 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1548 {
1549     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1550     return IAudioClient_AddRef(&This->IAudioClient_iface);
1551 }
1552
1553 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1554 {
1555     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1556     return IAudioClient_Release(&This->IAudioClient_iface);
1557 }
1558
1559 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1560         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1561         UINT64 *qpcpos)
1562 {
1563     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1564     HRESULT hr;
1565
1566     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1567             devpos, qpcpos);
1568
1569     if(!data || !frames || !flags)
1570         return E_POINTER;
1571
1572     EnterCriticalSection(&This->lock);
1573
1574     if(This->buf_state != NOT_LOCKED){
1575         LeaveCriticalSection(&This->lock);
1576         return AUDCLNT_E_OUT_OF_ORDER;
1577     }
1578
1579     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1580     if(FAILED(hr)){
1581         LeaveCriticalSection(&This->lock);
1582         return hr;
1583     }
1584
1585     *flags = 0;
1586
1587     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1588         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1589         if(This->tmp_buffer_frames < *frames){
1590             if(This->tmp_buffer)
1591                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1592                         This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1593             else
1594                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1595                         *frames * This->fmt->nBlockAlign);
1596             if(!This->tmp_buffer){
1597                 LeaveCriticalSection(&This->lock);
1598                 return E_OUTOFMEMORY;
1599             }
1600             This->tmp_buffer_frames = *frames;
1601         }
1602
1603         *data = This->tmp_buffer;
1604         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1605             This->fmt->nBlockAlign;
1606         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1607         frames_bytes = *frames * This->fmt->nBlockAlign;
1608         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1609         memcpy(This->tmp_buffer, This->local_buffer,
1610                 frames_bytes - chunk_bytes);
1611     }else
1612         *data = This->local_buffer +
1613             This->lcl_offs_frames * This->fmt->nBlockAlign;
1614
1615     This->buf_state = LOCKED_NORMAL;
1616
1617     if(devpos || qpcpos)
1618         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1619
1620     LeaveCriticalSection(&This->lock);
1621
1622     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1623 }
1624
1625 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1626         IAudioCaptureClient *iface, UINT32 done)
1627 {
1628     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1629
1630     TRACE("(%p)->(%u)\n", This, done);
1631
1632     EnterCriticalSection(&This->lock);
1633
1634     if(This->buf_state == NOT_LOCKED){
1635         LeaveCriticalSection(&This->lock);
1636         return AUDCLNT_E_OUT_OF_ORDER;
1637     }
1638
1639     This->held_frames -= done;
1640     This->lcl_offs_frames += done;
1641     This->lcl_offs_frames %= This->bufsize_frames;
1642
1643     This->buf_state = NOT_LOCKED;
1644
1645     LeaveCriticalSection(&This->lock);
1646
1647     return S_OK;
1648 }
1649
1650 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1651         IAudioCaptureClient *iface, UINT32 *frames)
1652 {
1653     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1654
1655     TRACE("(%p)->(%p)\n", This, frames);
1656
1657     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1658 }
1659
1660 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1661 {
1662     AudioCaptureClient_QueryInterface,
1663     AudioCaptureClient_AddRef,
1664     AudioCaptureClient_Release,
1665     AudioCaptureClient_GetBuffer,
1666     AudioCaptureClient_ReleaseBuffer,
1667     AudioCaptureClient_GetNextPacketSize
1668 };
1669
1670 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1671 {
1672     AudioSessionWrapper *ret;
1673
1674     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1675             sizeof(AudioSessionWrapper));
1676     if(!ret)
1677         return NULL;
1678
1679     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1680
1681     ret->client = client;
1682     ret->session = client->session;
1683     AudioClient_AddRef(&client->IAudioClient_iface);
1684
1685     return ret;
1686 }
1687
1688 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1689         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
1690 {
1691     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1692
1693     if(!ppv)
1694         return E_POINTER;
1695     *ppv = NULL;
1696
1697     if(IsEqualIID(riid, &IID_IUnknown) ||
1698             IsEqualIID(riid, &IID_IAudioSessionControl) ||
1699             IsEqualIID(riid, &IID_IAudioSessionControl2))
1700         *ppv = iface;
1701     if(*ppv){
1702         IUnknown_AddRef((IUnknown*)*ppv);
1703         return S_OK;
1704     }
1705
1706     WARN("Unknown interface %s\n", debugstr_guid(riid));
1707     return E_NOINTERFACE;
1708 }
1709
1710 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
1711 {
1712     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1713     ULONG ref;
1714     ref = InterlockedIncrement(&This->ref);
1715     TRACE("(%p) Refcount now %u\n", This, ref);
1716     return ref;
1717 }
1718
1719 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
1720 {
1721     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1722     ULONG ref;
1723     ref = InterlockedDecrement(&This->ref);
1724     TRACE("(%p) Refcount now %u\n", This, ref);
1725     if(!ref){
1726         EnterCriticalSection(&This->client->lock);
1727         This->client->session_wrapper = NULL;
1728         LeaveCriticalSection(&This->client->lock);
1729         AudioClient_Release(&This->client->IAudioClient_iface);
1730         HeapFree(GetProcessHeap(), 0, This);
1731     }
1732     return ref;
1733 }
1734
1735 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
1736         AudioSessionState *state)
1737 {
1738     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1739     ACImpl *client;
1740
1741     TRACE("(%p)->(%p)\n", This, state);
1742
1743     if(!state)
1744         return NULL_PTR_ERR;
1745
1746     EnterCriticalSection(&g_sessions_lock);
1747
1748     if(list_empty(&This->session->clients)){
1749         *state = AudioSessionStateExpired;
1750         LeaveCriticalSection(&g_sessions_lock);
1751         return S_OK;
1752     }
1753
1754     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
1755         EnterCriticalSection(&client->lock);
1756         if(client->playing){
1757             *state = AudioSessionStateActive;
1758             LeaveCriticalSection(&client->lock);
1759             LeaveCriticalSection(&g_sessions_lock);
1760             return S_OK;
1761         }
1762         LeaveCriticalSection(&client->lock);
1763     }
1764
1765     LeaveCriticalSection(&g_sessions_lock);
1766
1767     *state = AudioSessionStateInactive;
1768
1769     return S_OK;
1770 }
1771
1772 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
1773         IAudioSessionControl2 *iface, WCHAR **name)
1774 {
1775     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1776
1777     FIXME("(%p)->(%p) - stub\n", This, name);
1778
1779     return E_NOTIMPL;
1780 }
1781
1782 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
1783         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
1784 {
1785     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1786
1787     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
1788
1789     return E_NOTIMPL;
1790 }
1791
1792 static HRESULT WINAPI AudioSessionControl_GetIconPath(
1793         IAudioSessionControl2 *iface, WCHAR **path)
1794 {
1795     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1796
1797     FIXME("(%p)->(%p) - stub\n", This, path);
1798
1799     return E_NOTIMPL;
1800 }
1801
1802 static HRESULT WINAPI AudioSessionControl_SetIconPath(
1803         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
1804 {
1805     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1806
1807     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
1808
1809     return E_NOTIMPL;
1810 }
1811
1812 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
1813         IAudioSessionControl2 *iface, GUID *group)
1814 {
1815     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1816
1817     FIXME("(%p)->(%p) - stub\n", This, group);
1818
1819     return E_NOTIMPL;
1820 }
1821
1822 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
1823         IAudioSessionControl2 *iface, GUID *group, const GUID *session)
1824 {
1825     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1826
1827     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
1828             debugstr_guid(session));
1829
1830     return E_NOTIMPL;
1831 }
1832
1833 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
1834         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1835 {
1836     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1837
1838     FIXME("(%p)->(%p) - stub\n", This, events);
1839
1840     return S_OK;
1841 }
1842
1843 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
1844         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
1845 {
1846     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1847
1848     FIXME("(%p)->(%p) - stub\n", This, events);
1849
1850     return S_OK;
1851 }
1852
1853 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
1854         IAudioSessionControl2 *iface, WCHAR **id)
1855 {
1856     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1857
1858     FIXME("(%p)->(%p) - stub\n", This, id);
1859
1860     return E_NOTIMPL;
1861 }
1862
1863 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
1864         IAudioSessionControl2 *iface, WCHAR **id)
1865 {
1866     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1867
1868     FIXME("(%p)->(%p) - stub\n", This, id);
1869
1870     return E_NOTIMPL;
1871 }
1872
1873 static HRESULT WINAPI AudioSessionControl_GetProcessId(
1874         IAudioSessionControl2 *iface, DWORD *pid)
1875 {
1876     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1877
1878     TRACE("(%p)->(%p)\n", This, pid);
1879
1880     if(!pid)
1881         return E_POINTER;
1882
1883     *pid = GetCurrentProcessId();
1884
1885     return S_OK;
1886 }
1887
1888 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
1889         IAudioSessionControl2 *iface)
1890 {
1891     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1892
1893     TRACE("(%p)\n", This);
1894
1895     return S_FALSE;
1896 }
1897
1898 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
1899         IAudioSessionControl2 *iface, BOOL optout)
1900 {
1901     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
1902
1903     TRACE("(%p)->(%d)\n", This, optout);
1904
1905     return S_OK;
1906 }
1907
1908 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
1909 {
1910     AudioSessionControl_QueryInterface,
1911     AudioSessionControl_AddRef,
1912     AudioSessionControl_Release,
1913     AudioSessionControl_GetState,
1914     AudioSessionControl_GetDisplayName,
1915     AudioSessionControl_SetDisplayName,
1916     AudioSessionControl_GetIconPath,
1917     AudioSessionControl_SetIconPath,
1918     AudioSessionControl_GetGroupingParam,
1919     AudioSessionControl_SetGroupingParam,
1920     AudioSessionControl_RegisterAudioSessionNotification,
1921     AudioSessionControl_UnregisterAudioSessionNotification,
1922     AudioSessionControl_GetSessionIdentifier,
1923     AudioSessionControl_GetSessionInstanceIdentifier,
1924     AudioSessionControl_GetProcessId,
1925     AudioSessionControl_IsSystemSoundsSession,
1926     AudioSessionControl_SetDuckingPreference
1927 };
1928
1929 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
1930         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
1931 {
1932     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1933
1934     if(!ppv)
1935         return E_POINTER;
1936     *ppv = NULL;
1937
1938     if(IsEqualIID(riid, &IID_IUnknown) ||
1939             IsEqualIID(riid, &IID_ISimpleAudioVolume))
1940         *ppv = iface;
1941     if(*ppv){
1942         IUnknown_AddRef((IUnknown*)*ppv);
1943         return S_OK;
1944     }
1945
1946     WARN("Unknown interface %s\n", debugstr_guid(riid));
1947     return E_NOINTERFACE;
1948 }
1949
1950 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
1951 {
1952     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1953     return IAudioClient_AddRef(&This->IAudioClient_iface);
1954 }
1955
1956 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
1957 {
1958     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1959     return IAudioClient_Release(&This->IAudioClient_iface);
1960 }
1961
1962 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
1963         ISimpleAudioVolume *iface, float level, const GUID *context)
1964 {
1965     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1966
1967     FIXME("(%p)->(%f, %p) - stub\n", This, level, context);
1968
1969     return E_NOTIMPL;
1970 }
1971
1972 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
1973         ISimpleAudioVolume *iface, float *level)
1974 {
1975     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1976
1977     FIXME("(%p)->(%p) - stub\n", This, level);
1978
1979     return E_NOTIMPL;
1980 }
1981
1982 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
1983         BOOL mute, const GUID *context)
1984 {
1985     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1986
1987     FIXME("(%p)->(%u, %p) - stub\n", This, mute, context);
1988
1989     return E_NOTIMPL;
1990 }
1991
1992 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
1993         BOOL *mute)
1994 {
1995     ACImpl *This = impl_from_ISimpleAudioVolume(iface);
1996
1997     FIXME("(%p)->(%p) - stub\n", This, mute);
1998
1999     return E_NOTIMPL;
2000 }
2001
2002 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2003 {
2004     SimpleAudioVolume_QueryInterface,
2005     SimpleAudioVolume_AddRef,
2006     SimpleAudioVolume_Release,
2007     SimpleAudioVolume_SetMasterVolume,
2008     SimpleAudioVolume_GetMasterVolume,
2009     SimpleAudioVolume_SetMute,
2010     SimpleAudioVolume_GetMute
2011 };
2012
2013 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
2014         REFIID riid, void **ppv)
2015 {
2016     ACImpl *This = impl_from_IAudioClock(iface);
2017
2018     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2019
2020     if(!ppv)
2021         return E_POINTER;
2022     *ppv = NULL;
2023
2024     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2025         *ppv = iface;
2026     else if(IsEqualIID(riid, &IID_IAudioClock2))
2027         *ppv = &This->IAudioClock2_iface;
2028     if(*ppv){
2029         IUnknown_AddRef((IUnknown*)*ppv);
2030         return S_OK;
2031     }
2032
2033     WARN("Unknown interface %s\n", debugstr_guid(riid));
2034     return E_NOINTERFACE;
2035 }
2036
2037 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2038 {
2039     ACImpl *This = impl_from_IAudioClock(iface);
2040     return IAudioClient_AddRef(&This->IAudioClient_iface);
2041 }
2042
2043 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2044 {
2045     ACImpl *This = impl_from_IAudioClock(iface);
2046     return IAudioClient_Release(&This->IAudioClient_iface);
2047 }
2048
2049 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2050 {
2051     ACImpl *This = impl_from_IAudioClock(iface);
2052
2053     TRACE("(%p)->(%p)\n", This, freq);
2054
2055     *freq = This->fmt->nSamplesPerSec;
2056
2057     return S_OK;
2058 }
2059
2060 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2061         UINT64 *qpctime)
2062 {
2063     ACImpl *This = impl_from_IAudioClock(iface);
2064     UINT32 pad;
2065     HRESULT hr;
2066
2067     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2068
2069     if(!pos)
2070         return E_POINTER;
2071
2072     EnterCriticalSection(&This->lock);
2073
2074     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2075     if(FAILED(hr)){
2076         LeaveCriticalSection(&This->lock);
2077         return hr;
2078     }
2079
2080     if(This->dataflow == eRender)
2081         *pos = This->written_frames - pad;
2082     else if(This->dataflow == eCapture)
2083         *pos = This->written_frames + pad;
2084
2085     LeaveCriticalSection(&This->lock);
2086
2087     if(qpctime){
2088         LARGE_INTEGER stamp, freq;
2089         QueryPerformanceCounter(&stamp);
2090         QueryPerformanceFrequency(&freq);
2091         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2092     }
2093
2094     return S_OK;
2095 }
2096
2097 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2098         DWORD *chars)
2099 {
2100     ACImpl *This = impl_from_IAudioClock(iface);
2101
2102     TRACE("(%p)->(%p)\n", This, chars);
2103
2104     if(!chars)
2105         return E_POINTER;
2106
2107     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2108
2109     return S_OK;
2110 }
2111
2112 static const IAudioClockVtbl AudioClock_Vtbl =
2113 {
2114     AudioClock_QueryInterface,
2115     AudioClock_AddRef,
2116     AudioClock_Release,
2117     AudioClock_GetFrequency,
2118     AudioClock_GetPosition,
2119     AudioClock_GetCharacteristics
2120 };
2121
2122 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2123         REFIID riid, void **ppv)
2124 {
2125     ACImpl *This = impl_from_IAudioClock2(iface);
2126     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2127 }
2128
2129 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2130 {
2131     ACImpl *This = impl_from_IAudioClock2(iface);
2132     return IAudioClient_AddRef(&This->IAudioClient_iface);
2133 }
2134
2135 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2136 {
2137     ACImpl *This = impl_from_IAudioClock2(iface);
2138     return IAudioClient_Release(&This->IAudioClient_iface);
2139 }
2140
2141 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2142         UINT64 *pos, UINT64 *qpctime)
2143 {
2144     ACImpl *This = impl_from_IAudioClock2(iface);
2145
2146     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2147
2148     return E_NOTIMPL;
2149 }
2150
2151 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2152 {
2153     AudioClock2_QueryInterface,
2154     AudioClock2_AddRef,
2155     AudioClock2_Release,
2156     AudioClock2_GetDevicePosition
2157 };