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