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