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