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