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