mshtml: Added IOleContainer::EnumObjects tests.
[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_SURROUND; /* Vista deprecates 7POINT1 */
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     if(This->dataflow == eRender){
1505         This->written_frames = 0;
1506     }else{
1507         This->written_frames += This->held_frames;
1508     }
1509     This->lcl_offs_frames = 0;
1510     This->inbuf_frames = 0;
1511     This->held_frames = 0;
1512
1513     if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1514         WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1515
1516     LeaveCriticalSection(&This->lock);
1517
1518     return S_OK;
1519 }
1520
1521 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1522         HANDLE event)
1523 {
1524     ACImpl *This = impl_from_IAudioClient(iface);
1525
1526     TRACE("(%p)->(%p)\n", This, event);
1527
1528     if(!event)
1529         return E_INVALIDARG;
1530
1531     EnterCriticalSection(&This->lock);
1532
1533     if(!This->initted){
1534         LeaveCriticalSection(&This->lock);
1535         return AUDCLNT_E_NOT_INITIALIZED;
1536     }
1537
1538     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1539         LeaveCriticalSection(&This->lock);
1540         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1541     }
1542
1543     This->event = event;
1544
1545     LeaveCriticalSection(&This->lock);
1546
1547     return S_OK;
1548 }
1549
1550 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1551         void **ppv)
1552 {
1553     ACImpl *This = impl_from_IAudioClient(iface);
1554
1555     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1556
1557     if(!ppv)
1558         return E_POINTER;
1559     *ppv = NULL;
1560
1561     EnterCriticalSection(&This->lock);
1562
1563     if(!This->initted){
1564         LeaveCriticalSection(&This->lock);
1565         return AUDCLNT_E_NOT_INITIALIZED;
1566     }
1567
1568     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1569         if(This->dataflow != eRender){
1570             LeaveCriticalSection(&This->lock);
1571             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1572         }
1573         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1574         *ppv = &This->IAudioRenderClient_iface;
1575     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1576         if(This->dataflow != eCapture){
1577             LeaveCriticalSection(&This->lock);
1578             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1579         }
1580         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1581         *ppv = &This->IAudioCaptureClient_iface;
1582     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1583         IAudioClock_AddRef(&This->IAudioClock_iface);
1584         *ppv = &This->IAudioClock_iface;
1585     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1586         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1587         *ppv = &This->IAudioStreamVolume_iface;
1588     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1589         if(!This->session_wrapper){
1590             This->session_wrapper = AudioSessionWrapper_Create(This);
1591             if(!This->session_wrapper){
1592                 LeaveCriticalSection(&This->lock);
1593                 return E_OUTOFMEMORY;
1594             }
1595         }else
1596             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1597
1598         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1599     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1600         if(!This->session_wrapper){
1601             This->session_wrapper = AudioSessionWrapper_Create(This);
1602             if(!This->session_wrapper){
1603                 LeaveCriticalSection(&This->lock);
1604                 return E_OUTOFMEMORY;
1605             }
1606         }else
1607             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1608
1609         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1610     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1611         if(!This->session_wrapper){
1612             This->session_wrapper = AudioSessionWrapper_Create(This);
1613             if(!This->session_wrapper){
1614                 LeaveCriticalSection(&This->lock);
1615                 return E_OUTOFMEMORY;
1616             }
1617         }else
1618             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1619
1620         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1621     }
1622
1623     if(*ppv){
1624         LeaveCriticalSection(&This->lock);
1625         return S_OK;
1626     }
1627
1628     LeaveCriticalSection(&This->lock);
1629
1630     FIXME("stub %s\n", debugstr_guid(riid));
1631     return E_NOINTERFACE;
1632 }
1633
1634 static const IAudioClientVtbl AudioClient_Vtbl =
1635 {
1636     AudioClient_QueryInterface,
1637     AudioClient_AddRef,
1638     AudioClient_Release,
1639     AudioClient_Initialize,
1640     AudioClient_GetBufferSize,
1641     AudioClient_GetStreamLatency,
1642     AudioClient_GetCurrentPadding,
1643     AudioClient_IsFormatSupported,
1644     AudioClient_GetMixFormat,
1645     AudioClient_GetDevicePeriod,
1646     AudioClient_Start,
1647     AudioClient_Stop,
1648     AudioClient_Reset,
1649     AudioClient_SetEventHandle,
1650     AudioClient_GetService
1651 };
1652
1653 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1654         IAudioRenderClient *iface, REFIID riid, void **ppv)
1655 {
1656     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1657
1658     if(!ppv)
1659         return E_POINTER;
1660     *ppv = NULL;
1661
1662     if(IsEqualIID(riid, &IID_IUnknown) ||
1663             IsEqualIID(riid, &IID_IAudioRenderClient))
1664         *ppv = iface;
1665     if(*ppv){
1666         IUnknown_AddRef((IUnknown*)*ppv);
1667         return S_OK;
1668     }
1669
1670     WARN("Unknown interface %s\n", debugstr_guid(riid));
1671     return E_NOINTERFACE;
1672 }
1673
1674 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1675 {
1676     ACImpl *This = impl_from_IAudioRenderClient(iface);
1677     return AudioClient_AddRef(&This->IAudioClient_iface);
1678 }
1679
1680 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1681 {
1682     ACImpl *This = impl_from_IAudioRenderClient(iface);
1683     return AudioClient_Release(&This->IAudioClient_iface);
1684 }
1685
1686 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1687         UINT32 frames, BYTE **data)
1688 {
1689     ACImpl *This = impl_from_IAudioRenderClient(iface);
1690     UINT32 pad, write_pos;
1691     HRESULT hr;
1692
1693     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1694
1695     if(!data)
1696         return E_POINTER;
1697
1698     *data = NULL;
1699
1700     EnterCriticalSection(&This->lock);
1701
1702     if(This->getbuf_last){
1703         LeaveCriticalSection(&This->lock);
1704         return AUDCLNT_E_OUT_OF_ORDER;
1705     }
1706
1707     if(!frames){
1708         LeaveCriticalSection(&This->lock);
1709         return S_OK;
1710     }
1711
1712     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1713     if(FAILED(hr)){
1714         LeaveCriticalSection(&This->lock);
1715         return hr;
1716     }
1717
1718     if(pad + frames > This->bufsize_frames){
1719         LeaveCriticalSection(&This->lock);
1720         return AUDCLNT_E_BUFFER_TOO_LARGE;
1721     }
1722
1723     write_pos =
1724         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1725     if(write_pos + frames > This->bufsize_frames){
1726         if(This->tmp_buffer_frames < frames){
1727             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1728             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1729                     frames * This->fmt->nBlockAlign);
1730             if(!This->tmp_buffer){
1731                 LeaveCriticalSection(&This->lock);
1732                 return E_OUTOFMEMORY;
1733             }
1734             This->tmp_buffer_frames = frames;
1735         }
1736         *data = This->tmp_buffer;
1737         This->getbuf_last = -frames;
1738     }else{
1739         *data = This->local_buffer + write_pos * This->fmt->nBlockAlign;
1740         This->getbuf_last = frames;
1741     }
1742
1743     LeaveCriticalSection(&This->lock);
1744
1745     return S_OK;
1746 }
1747
1748 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_frames)
1749 {
1750     UINT32 write_offs_frames =
1751         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1752     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1753     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1754     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1755     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1756
1757     if(written_bytes <= chunk_bytes){
1758         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1759     }else{
1760         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1761         memcpy(This->local_buffer, buffer + chunk_bytes,
1762                 written_bytes - chunk_bytes);
1763     }
1764 }
1765
1766 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1767         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1768 {
1769     ACImpl *This = impl_from_IAudioRenderClient(iface);
1770     BYTE *buffer;
1771
1772     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1773
1774     EnterCriticalSection(&This->lock);
1775
1776     if(!written_frames){
1777         This->getbuf_last = 0;
1778         LeaveCriticalSection(&This->lock);
1779         return S_OK;
1780     }
1781
1782     if(!This->getbuf_last){
1783         LeaveCriticalSection(&This->lock);
1784         return AUDCLNT_E_OUT_OF_ORDER;
1785     }
1786
1787     if(written_frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
1788         LeaveCriticalSection(&This->lock);
1789         return AUDCLNT_E_INVALID_SIZE;
1790     }
1791
1792     if(This->getbuf_last >= 0)
1793         buffer = This->local_buffer + This->fmt->nBlockAlign *
1794           ((This->lcl_offs_frames + This->held_frames) % This->bufsize_frames);
1795     else
1796         buffer = This->tmp_buffer;
1797
1798     if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1799         oss_silence_buffer(This, buffer, written_frames);
1800
1801     if(This->held_frames){
1802         if(This->getbuf_last < 0)
1803             oss_wrap_buffer(This, buffer, written_frames);
1804
1805         This->held_frames += written_frames;
1806     }else{
1807         ssize_t w_bytes;
1808         UINT32 w_frames;
1809
1810         if(This->session->mute)
1811             oss_silence_buffer(This, buffer, written_frames);
1812
1813         w_bytes = write(This->fd, buffer,
1814                 written_frames * This->fmt->nBlockAlign);
1815         if(w_bytes < 0){
1816             if(errno != EAGAIN){
1817                 This->getbuf_last = 0;
1818                 LeaveCriticalSection(&This->lock);
1819                 ERR("write failed: %d (%s)\n", errno, strerror(errno));
1820                 return E_FAIL;
1821             }else /* OSS buffer full */
1822                 w_bytes = 0;
1823         }
1824         w_frames = w_bytes / This->fmt->nBlockAlign;
1825         This->inbuf_frames += w_frames;
1826
1827         if(w_frames < written_frames){
1828             if(This->getbuf_last < 0)
1829                 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1830                         written_frames - w_frames);
1831             else
1832                 This->lcl_offs_frames += w_frames;
1833             This->held_frames = written_frames - w_frames;
1834         }
1835     }
1836
1837     This->written_frames += written_frames;
1838     This->getbuf_last = 0;
1839
1840     LeaveCriticalSection(&This->lock);
1841
1842     return S_OK;
1843 }
1844
1845 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1846     AudioRenderClient_QueryInterface,
1847     AudioRenderClient_AddRef,
1848     AudioRenderClient_Release,
1849     AudioRenderClient_GetBuffer,
1850     AudioRenderClient_ReleaseBuffer
1851 };
1852
1853 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1854         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1855 {
1856     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1857
1858     if(!ppv)
1859         return E_POINTER;
1860     *ppv = NULL;
1861
1862     if(IsEqualIID(riid, &IID_IUnknown) ||
1863             IsEqualIID(riid, &IID_IAudioCaptureClient))
1864         *ppv = iface;
1865     if(*ppv){
1866         IUnknown_AddRef((IUnknown*)*ppv);
1867         return S_OK;
1868     }
1869
1870     WARN("Unknown interface %s\n", debugstr_guid(riid));
1871     return E_NOINTERFACE;
1872 }
1873
1874 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1875 {
1876     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1877     return IAudioClient_AddRef(&This->IAudioClient_iface);
1878 }
1879
1880 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1881 {
1882     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1883     return IAudioClient_Release(&This->IAudioClient_iface);
1884 }
1885
1886 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1887         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1888         UINT64 *qpcpos)
1889 {
1890     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1891     HRESULT hr;
1892
1893     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1894             devpos, qpcpos);
1895
1896     if(!data || !frames || !flags)
1897         return E_POINTER;
1898
1899     EnterCriticalSection(&This->lock);
1900
1901     if(This->buf_state != NOT_LOCKED){
1902         LeaveCriticalSection(&This->lock);
1903         return AUDCLNT_E_OUT_OF_ORDER;
1904     }
1905
1906     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1907     if(FAILED(hr)){
1908         LeaveCriticalSection(&This->lock);
1909         return hr;
1910     }
1911
1912     *flags = 0;
1913
1914     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1915         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1916         if(This->tmp_buffer_frames < *frames){
1917             if(This->tmp_buffer)
1918             HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1919             This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1920                     *frames * This->fmt->nBlockAlign);
1921             if(!This->tmp_buffer){
1922                 LeaveCriticalSection(&This->lock);
1923                 return E_OUTOFMEMORY;
1924             }
1925             This->tmp_buffer_frames = *frames;
1926         }
1927
1928         *data = This->tmp_buffer;
1929         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1930             This->fmt->nBlockAlign;
1931         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1932         frames_bytes = *frames * This->fmt->nBlockAlign;
1933         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1934         memcpy(This->tmp_buffer, This->local_buffer,
1935                 frames_bytes - chunk_bytes);
1936     }else
1937         *data = This->local_buffer +
1938             This->lcl_offs_frames * This->fmt->nBlockAlign;
1939
1940     This->buf_state = LOCKED_NORMAL;
1941
1942     if(devpos || qpcpos)
1943         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1944
1945     LeaveCriticalSection(&This->lock);
1946
1947     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1948 }
1949
1950 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1951         IAudioCaptureClient *iface, UINT32 done)
1952 {
1953     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1954
1955     TRACE("(%p)->(%u)\n", This, done);
1956
1957     EnterCriticalSection(&This->lock);
1958
1959     if(This->buf_state == NOT_LOCKED){
1960         LeaveCriticalSection(&This->lock);
1961         return AUDCLNT_E_OUT_OF_ORDER;
1962     }
1963
1964     This->held_frames -= done;
1965     This->lcl_offs_frames += done;
1966     This->lcl_offs_frames %= This->bufsize_frames;
1967
1968     This->buf_state = NOT_LOCKED;
1969
1970     LeaveCriticalSection(&This->lock);
1971
1972     return S_OK;
1973 }
1974
1975 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1976         IAudioCaptureClient *iface, UINT32 *frames)
1977 {
1978     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1979
1980     TRACE("(%p)->(%p)\n", This, frames);
1981
1982     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1983 }
1984
1985 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1986 {
1987     AudioCaptureClient_QueryInterface,
1988     AudioCaptureClient_AddRef,
1989     AudioCaptureClient_Release,
1990     AudioCaptureClient_GetBuffer,
1991     AudioCaptureClient_ReleaseBuffer,
1992     AudioCaptureClient_GetNextPacketSize
1993 };
1994
1995 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1996         REFIID riid, void **ppv)
1997 {
1998     ACImpl *This = impl_from_IAudioClock(iface);
1999
2000     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2001
2002     if(!ppv)
2003         return E_POINTER;
2004     *ppv = NULL;
2005
2006     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
2007         *ppv = iface;
2008     else if(IsEqualIID(riid, &IID_IAudioClock2))
2009         *ppv = &This->IAudioClock2_iface;
2010     if(*ppv){
2011         IUnknown_AddRef((IUnknown*)*ppv);
2012         return S_OK;
2013     }
2014
2015     WARN("Unknown interface %s\n", debugstr_guid(riid));
2016     return E_NOINTERFACE;
2017 }
2018
2019 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
2020 {
2021     ACImpl *This = impl_from_IAudioClock(iface);
2022     return IAudioClient_AddRef(&This->IAudioClient_iface);
2023 }
2024
2025 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
2026 {
2027     ACImpl *This = impl_from_IAudioClock(iface);
2028     return IAudioClient_Release(&This->IAudioClient_iface);
2029 }
2030
2031 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
2032 {
2033     ACImpl *This = impl_from_IAudioClock(iface);
2034
2035     TRACE("(%p)->(%p)\n", This, freq);
2036
2037     *freq = This->fmt->nSamplesPerSec;
2038
2039     return S_OK;
2040 }
2041
2042 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
2043         UINT64 *qpctime)
2044 {
2045     ACImpl *This = impl_from_IAudioClock(iface);
2046     UINT32 pad;
2047     HRESULT hr;
2048
2049     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
2050
2051     if(!pos)
2052         return E_POINTER;
2053
2054     EnterCriticalSection(&This->lock);
2055
2056     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
2057     if(FAILED(hr)){
2058         LeaveCriticalSection(&This->lock);
2059         return hr;
2060     }
2061
2062     if(This->dataflow == eRender)
2063         *pos = This->written_frames - pad;
2064     else if(This->dataflow == eCapture)
2065         *pos = This->written_frames + pad;
2066
2067     LeaveCriticalSection(&This->lock);
2068
2069     if(qpctime){
2070         LARGE_INTEGER stamp, freq;
2071         QueryPerformanceCounter(&stamp);
2072         QueryPerformanceFrequency(&freq);
2073         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
2074     }
2075
2076     return S_OK;
2077 }
2078
2079 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
2080         DWORD *chars)
2081 {
2082     ACImpl *This = impl_from_IAudioClock(iface);
2083
2084     TRACE("(%p)->(%p)\n", This, chars);
2085
2086     if(!chars)
2087         return E_POINTER;
2088
2089     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
2090
2091     return S_OK;
2092 }
2093
2094 static const IAudioClockVtbl AudioClock_Vtbl =
2095 {
2096     AudioClock_QueryInterface,
2097     AudioClock_AddRef,
2098     AudioClock_Release,
2099     AudioClock_GetFrequency,
2100     AudioClock_GetPosition,
2101     AudioClock_GetCharacteristics
2102 };
2103
2104 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
2105         REFIID riid, void **ppv)
2106 {
2107     ACImpl *This = impl_from_IAudioClock2(iface);
2108     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
2109 }
2110
2111 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
2112 {
2113     ACImpl *This = impl_from_IAudioClock2(iface);
2114     return IAudioClient_AddRef(&This->IAudioClient_iface);
2115 }
2116
2117 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
2118 {
2119     ACImpl *This = impl_from_IAudioClock2(iface);
2120     return IAudioClient_Release(&This->IAudioClient_iface);
2121 }
2122
2123 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
2124         UINT64 *pos, UINT64 *qpctime)
2125 {
2126     ACImpl *This = impl_from_IAudioClock2(iface);
2127
2128     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
2129
2130     return E_NOTIMPL;
2131 }
2132
2133 static const IAudioClock2Vtbl AudioClock2_Vtbl =
2134 {
2135     AudioClock2_QueryInterface,
2136     AudioClock2_AddRef,
2137     AudioClock2_Release,
2138     AudioClock2_GetDevicePosition
2139 };
2140
2141 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2142 {
2143     AudioSessionWrapper *ret;
2144
2145     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2146             sizeof(AudioSessionWrapper));
2147     if(!ret)
2148         return NULL;
2149
2150     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2151     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2152     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2153
2154     ret->ref = 1;
2155
2156     ret->client = client;
2157     if(client){
2158         ret->session = client->session;
2159         AudioClient_AddRef(&client->IAudioClient_iface);
2160     }
2161
2162     return ret;
2163 }
2164
2165 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2166         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2167 {
2168     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2169
2170     if(!ppv)
2171         return E_POINTER;
2172     *ppv = NULL;
2173
2174     if(IsEqualIID(riid, &IID_IUnknown) ||
2175             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2176             IsEqualIID(riid, &IID_IAudioSessionControl2))
2177         *ppv = iface;
2178     if(*ppv){
2179         IUnknown_AddRef((IUnknown*)*ppv);
2180         return S_OK;
2181     }
2182
2183     WARN("Unknown interface %s\n", debugstr_guid(riid));
2184     return E_NOINTERFACE;
2185 }
2186
2187 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2188 {
2189     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2190     ULONG ref;
2191     ref = InterlockedIncrement(&This->ref);
2192     TRACE("(%p) Refcount now %u\n", This, ref);
2193     return ref;
2194 }
2195
2196 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2197 {
2198     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2199     ULONG ref;
2200     ref = InterlockedDecrement(&This->ref);
2201     TRACE("(%p) Refcount now %u\n", This, ref);
2202     if(!ref){
2203         if(This->client){
2204             EnterCriticalSection(&This->client->lock);
2205             This->client->session_wrapper = NULL;
2206             LeaveCriticalSection(&This->client->lock);
2207             AudioClient_Release(&This->client->IAudioClient_iface);
2208         }
2209         HeapFree(GetProcessHeap(), 0, This);
2210     }
2211     return ref;
2212 }
2213
2214 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2215         AudioSessionState *state)
2216 {
2217     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2218     ACImpl *client;
2219
2220     TRACE("(%p)->(%p)\n", This, state);
2221
2222     if(!state)
2223         return NULL_PTR_ERR;
2224
2225     EnterCriticalSection(&g_sessions_lock);
2226
2227     if(list_empty(&This->session->clients)){
2228         *state = AudioSessionStateExpired;
2229         LeaveCriticalSection(&g_sessions_lock);
2230         return S_OK;
2231     }
2232
2233     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2234         EnterCriticalSection(&client->lock);
2235         if(client->playing){
2236             *state = AudioSessionStateActive;
2237             LeaveCriticalSection(&client->lock);
2238             LeaveCriticalSection(&g_sessions_lock);
2239             return S_OK;
2240         }
2241         LeaveCriticalSection(&client->lock);
2242     }
2243
2244     LeaveCriticalSection(&g_sessions_lock);
2245
2246     *state = AudioSessionStateInactive;
2247
2248     return S_OK;
2249 }
2250
2251 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2252         IAudioSessionControl2 *iface, WCHAR **name)
2253 {
2254     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2255
2256     FIXME("(%p)->(%p) - stub\n", This, name);
2257
2258     return E_NOTIMPL;
2259 }
2260
2261 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2262         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2263 {
2264     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2265
2266     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2267
2268     return E_NOTIMPL;
2269 }
2270
2271 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2272         IAudioSessionControl2 *iface, WCHAR **path)
2273 {
2274     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2275
2276     FIXME("(%p)->(%p) - stub\n", This, path);
2277
2278     return E_NOTIMPL;
2279 }
2280
2281 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2282         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2283 {
2284     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2285
2286     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2287
2288     return E_NOTIMPL;
2289 }
2290
2291 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2292         IAudioSessionControl2 *iface, GUID *group)
2293 {
2294     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2295
2296     FIXME("(%p)->(%p) - stub\n", This, group);
2297
2298     return E_NOTIMPL;
2299 }
2300
2301 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2302         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2303 {
2304     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2305
2306     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2307             debugstr_guid(session));
2308
2309     return E_NOTIMPL;
2310 }
2311
2312 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2313         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2314 {
2315     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2316
2317     FIXME("(%p)->(%p) - stub\n", This, events);
2318
2319     return S_OK;
2320 }
2321
2322 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2323         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2324 {
2325     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2326
2327     FIXME("(%p)->(%p) - stub\n", This, events);
2328
2329     return S_OK;
2330 }
2331
2332 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2333         IAudioSessionControl2 *iface, WCHAR **id)
2334 {
2335     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2336
2337     FIXME("(%p)->(%p) - stub\n", This, id);
2338
2339     return E_NOTIMPL;
2340 }
2341
2342 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2343         IAudioSessionControl2 *iface, WCHAR **id)
2344 {
2345     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2346
2347     FIXME("(%p)->(%p) - stub\n", This, id);
2348
2349     return E_NOTIMPL;
2350 }
2351
2352 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2353         IAudioSessionControl2 *iface, DWORD *pid)
2354 {
2355     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2356
2357     TRACE("(%p)->(%p)\n", This, pid);
2358
2359     if(!pid)
2360         return E_POINTER;
2361
2362     *pid = GetCurrentProcessId();
2363
2364     return S_OK;
2365 }
2366
2367 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2368         IAudioSessionControl2 *iface)
2369 {
2370     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2371
2372     TRACE("(%p)\n", This);
2373
2374     return S_FALSE;
2375 }
2376
2377 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2378         IAudioSessionControl2 *iface, BOOL optout)
2379 {
2380     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2381
2382     TRACE("(%p)->(%d)\n", This, optout);
2383
2384     return S_OK;
2385 }
2386
2387 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2388 {
2389     AudioSessionControl_QueryInterface,
2390     AudioSessionControl_AddRef,
2391     AudioSessionControl_Release,
2392     AudioSessionControl_GetState,
2393     AudioSessionControl_GetDisplayName,
2394     AudioSessionControl_SetDisplayName,
2395     AudioSessionControl_GetIconPath,
2396     AudioSessionControl_SetIconPath,
2397     AudioSessionControl_GetGroupingParam,
2398     AudioSessionControl_SetGroupingParam,
2399     AudioSessionControl_RegisterAudioSessionNotification,
2400     AudioSessionControl_UnregisterAudioSessionNotification,
2401     AudioSessionControl_GetSessionIdentifier,
2402     AudioSessionControl_GetSessionInstanceIdentifier,
2403     AudioSessionControl_GetProcessId,
2404     AudioSessionControl_IsSystemSoundsSession,
2405     AudioSessionControl_SetDuckingPreference
2406 };
2407
2408 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2409         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2410 {
2411     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2412
2413     if(!ppv)
2414         return E_POINTER;
2415     *ppv = NULL;
2416
2417     if(IsEqualIID(riid, &IID_IUnknown) ||
2418             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2419         *ppv = iface;
2420     if(*ppv){
2421         IUnknown_AddRef((IUnknown*)*ppv);
2422         return S_OK;
2423     }
2424
2425     WARN("Unknown interface %s\n", debugstr_guid(riid));
2426     return E_NOINTERFACE;
2427 }
2428
2429 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2430 {
2431     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2432     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2433 }
2434
2435 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2436 {
2437     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2438     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2439 }
2440
2441 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2442         ISimpleAudioVolume *iface, float level, const GUID *context)
2443 {
2444     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2445     AudioSession *session = This->session;
2446
2447     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2448
2449     if(level < 0.f || level > 1.f)
2450         return E_INVALIDARG;
2451
2452     if(context)
2453         FIXME("Notifications not supported yet\n");
2454
2455     EnterCriticalSection(&session->lock);
2456
2457     session->master_vol = level;
2458
2459     TRACE("OSS doesn't support setting volume\n");
2460
2461     LeaveCriticalSection(&session->lock);
2462
2463     return S_OK;
2464 }
2465
2466 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2467         ISimpleAudioVolume *iface, float *level)
2468 {
2469     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2470     AudioSession *session = This->session;
2471
2472     TRACE("(%p)->(%p)\n", session, level);
2473
2474     if(!level)
2475         return NULL_PTR_ERR;
2476
2477     *level = session->master_vol;
2478
2479     return S_OK;
2480 }
2481
2482 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2483         BOOL mute, const GUID *context)
2484 {
2485     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2486     AudioSession *session = This->session;
2487
2488     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2489
2490     EnterCriticalSection(&session->lock);
2491
2492     if(!mute && session->mute){
2493         ACImpl *client;
2494
2495         session->mute = mute;
2496
2497         LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2498             EnterCriticalSection(&client->lock);
2499             if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2500                 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2501                         strerror(errno));
2502             oss_write_data(client);
2503             LeaveCriticalSection(&client->lock);
2504         }
2505     }else
2506         session->mute = mute;
2507
2508     LeaveCriticalSection(&session->lock);
2509
2510     return S_OK;
2511 }
2512
2513 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2514         BOOL *mute)
2515 {
2516     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2517     AudioSession *session = This->session;
2518
2519     TRACE("(%p)->(%p)\n", session, mute);
2520
2521     if(!mute)
2522         return NULL_PTR_ERR;
2523
2524     *mute = This->session->mute;
2525
2526     return S_OK;
2527 }
2528
2529 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2530 {
2531     SimpleAudioVolume_QueryInterface,
2532     SimpleAudioVolume_AddRef,
2533     SimpleAudioVolume_Release,
2534     SimpleAudioVolume_SetMasterVolume,
2535     SimpleAudioVolume_GetMasterVolume,
2536     SimpleAudioVolume_SetMute,
2537     SimpleAudioVolume_GetMute
2538 };
2539
2540 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2541         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2542 {
2543     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2544
2545     if(!ppv)
2546         return E_POINTER;
2547     *ppv = NULL;
2548
2549     if(IsEqualIID(riid, &IID_IUnknown) ||
2550             IsEqualIID(riid, &IID_IAudioStreamVolume))
2551         *ppv = iface;
2552     if(*ppv){
2553         IUnknown_AddRef((IUnknown*)*ppv);
2554         return S_OK;
2555     }
2556
2557     WARN("Unknown interface %s\n", debugstr_guid(riid));
2558     return E_NOINTERFACE;
2559 }
2560
2561 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2562 {
2563     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2564     return IAudioClient_AddRef(&This->IAudioClient_iface);
2565 }
2566
2567 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2568 {
2569     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2570     return IAudioClient_Release(&This->IAudioClient_iface);
2571 }
2572
2573 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2574         IAudioStreamVolume *iface, UINT32 *out)
2575 {
2576     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2577
2578     TRACE("(%p)->(%p)\n", This, out);
2579
2580     if(!out)
2581         return E_POINTER;
2582
2583     *out = This->fmt->nChannels;
2584
2585     return S_OK;
2586 }
2587
2588 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2589         IAudioStreamVolume *iface, UINT32 index, float level)
2590 {
2591     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2592
2593     TRACE("(%p)->(%d, %f)\n", This, index, level);
2594
2595     if(level < 0.f || level > 1.f)
2596         return E_INVALIDARG;
2597
2598     if(index >= This->fmt->nChannels)
2599         return E_INVALIDARG;
2600
2601     EnterCriticalSection(&This->lock);
2602
2603     This->vols[index] = level;
2604
2605     TRACE("OSS doesn't support setting volume\n");
2606
2607     LeaveCriticalSection(&This->lock);
2608
2609     return S_OK;
2610 }
2611
2612 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2613         IAudioStreamVolume *iface, UINT32 index, float *level)
2614 {
2615     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2616
2617     TRACE("(%p)->(%d, %p)\n", This, index, level);
2618
2619     if(!level)
2620         return E_POINTER;
2621
2622     if(index >= This->fmt->nChannels)
2623         return E_INVALIDARG;
2624
2625     *level = This->vols[index];
2626
2627     return S_OK;
2628 }
2629
2630 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2631         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2632 {
2633     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2634     int i;
2635
2636     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2637
2638     if(!levels)
2639         return E_POINTER;
2640
2641     if(count != This->fmt->nChannels)
2642         return E_INVALIDARG;
2643
2644     EnterCriticalSection(&This->lock);
2645
2646     for(i = 0; i < count; ++i)
2647         This->vols[i] = levels[i];
2648
2649     TRACE("OSS doesn't support setting volume\n");
2650
2651     LeaveCriticalSection(&This->lock);
2652
2653     return S_OK;
2654 }
2655
2656 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2657         IAudioStreamVolume *iface, UINT32 count, float *levels)
2658 {
2659     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2660     int i;
2661
2662     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2663
2664     if(!levels)
2665         return E_POINTER;
2666
2667     if(count != This->fmt->nChannels)
2668         return E_INVALIDARG;
2669
2670     EnterCriticalSection(&This->lock);
2671
2672     for(i = 0; i < count; ++i)
2673         levels[i] = This->vols[i];
2674
2675     LeaveCriticalSection(&This->lock);
2676
2677     return S_OK;
2678 }
2679
2680 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2681 {
2682     AudioStreamVolume_QueryInterface,
2683     AudioStreamVolume_AddRef,
2684     AudioStreamVolume_Release,
2685     AudioStreamVolume_GetChannelCount,
2686     AudioStreamVolume_SetChannelVolume,
2687     AudioStreamVolume_GetChannelVolume,
2688     AudioStreamVolume_SetAllVolumes,
2689     AudioStreamVolume_GetAllVolumes
2690 };
2691
2692 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2693         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2694 {
2695     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2696
2697     if(!ppv)
2698         return E_POINTER;
2699     *ppv = NULL;
2700
2701     if(IsEqualIID(riid, &IID_IUnknown) ||
2702             IsEqualIID(riid, &IID_IChannelAudioVolume))
2703         *ppv = iface;
2704     if(*ppv){
2705         IUnknown_AddRef((IUnknown*)*ppv);
2706         return S_OK;
2707     }
2708
2709     WARN("Unknown interface %s\n", debugstr_guid(riid));
2710     return E_NOINTERFACE;
2711 }
2712
2713 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2714 {
2715     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2716     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2717 }
2718
2719 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2720 {
2721     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2722     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2723 }
2724
2725 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2726         IChannelAudioVolume *iface, UINT32 *out)
2727 {
2728     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2729     AudioSession *session = This->session;
2730
2731     TRACE("(%p)->(%p)\n", session, out);
2732
2733     if(!out)
2734         return NULL_PTR_ERR;
2735
2736     *out = session->channel_count;
2737
2738     return S_OK;
2739 }
2740
2741 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2742         IChannelAudioVolume *iface, UINT32 index, float level,
2743         const GUID *context)
2744 {
2745     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2746     AudioSession *session = This->session;
2747
2748     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2749             wine_dbgstr_guid(context));
2750
2751     if(level < 0.f || level > 1.f)
2752         return E_INVALIDARG;
2753
2754     if(index >= session->channel_count)
2755         return E_INVALIDARG;
2756
2757     if(context)
2758         FIXME("Notifications not supported yet\n");
2759
2760     EnterCriticalSection(&session->lock);
2761
2762     session->channel_vols[index] = level;
2763
2764     TRACE("OSS doesn't support setting volume\n");
2765
2766     LeaveCriticalSection(&session->lock);
2767
2768     return S_OK;
2769 }
2770
2771 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2772         IChannelAudioVolume *iface, UINT32 index, float *level)
2773 {
2774     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2775     AudioSession *session = This->session;
2776
2777     TRACE("(%p)->(%d, %p)\n", session, index, level);
2778
2779     if(!level)
2780         return NULL_PTR_ERR;
2781
2782     if(index >= session->channel_count)
2783         return E_INVALIDARG;
2784
2785     *level = session->channel_vols[index];
2786
2787     return S_OK;
2788 }
2789
2790 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2791         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2792         const GUID *context)
2793 {
2794     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2795     AudioSession *session = This->session;
2796     int i;
2797
2798     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2799             wine_dbgstr_guid(context));
2800
2801     if(!levels)
2802         return NULL_PTR_ERR;
2803
2804     if(count != session->channel_count)
2805         return E_INVALIDARG;
2806
2807     if(context)
2808         FIXME("Notifications not supported yet\n");
2809
2810     EnterCriticalSection(&session->lock);
2811
2812     for(i = 0; i < count; ++i)
2813         session->channel_vols[i] = levels[i];
2814
2815     TRACE("OSS doesn't support setting volume\n");
2816
2817     LeaveCriticalSection(&session->lock);
2818
2819     return S_OK;
2820 }
2821
2822 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2823         IChannelAudioVolume *iface, UINT32 count, float *levels)
2824 {
2825     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2826     AudioSession *session = This->session;
2827     int i;
2828
2829     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2830
2831     if(!levels)
2832         return NULL_PTR_ERR;
2833
2834     if(count != session->channel_count)
2835         return E_INVALIDARG;
2836
2837     for(i = 0; i < count; ++i)
2838         levels[i] = session->channel_vols[i];
2839
2840     return S_OK;
2841 }
2842
2843 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2844 {
2845     ChannelAudioVolume_QueryInterface,
2846     ChannelAudioVolume_AddRef,
2847     ChannelAudioVolume_Release,
2848     ChannelAudioVolume_GetChannelCount,
2849     ChannelAudioVolume_SetChannelVolume,
2850     ChannelAudioVolume_GetChannelVolume,
2851     ChannelAudioVolume_SetAllVolumes,
2852     ChannelAudioVolume_GetAllVolumes
2853 };
2854
2855 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2856         REFIID riid, void **ppv)
2857 {
2858     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2859
2860     if(!ppv)
2861         return E_POINTER;
2862     *ppv = NULL;
2863
2864     if(IsEqualIID(riid, &IID_IUnknown) ||
2865             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2866             IsEqualIID(riid, &IID_IAudioSessionManager2))
2867         *ppv = iface;
2868     if(*ppv){
2869         IUnknown_AddRef((IUnknown*)*ppv);
2870         return S_OK;
2871     }
2872
2873     WARN("Unknown interface %s\n", debugstr_guid(riid));
2874     return E_NOINTERFACE;
2875 }
2876
2877 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2878 {
2879     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2880     ULONG ref;
2881     ref = InterlockedIncrement(&This->ref);
2882     TRACE("(%p) Refcount now %u\n", This, ref);
2883     return ref;
2884 }
2885
2886 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2887 {
2888     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2889     ULONG ref;
2890     ref = InterlockedDecrement(&This->ref);
2891     TRACE("(%p) Refcount now %u\n", This, ref);
2892     if(!ref)
2893         HeapFree(GetProcessHeap(), 0, This);
2894     return ref;
2895 }
2896
2897 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2898         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2899         IAudioSessionControl **out)
2900 {
2901     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2902     AudioSession *session;
2903     AudioSessionWrapper *wrapper;
2904     HRESULT hr;
2905
2906     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2907             flags, out);
2908
2909     hr = get_audio_session(session_guid, This->device, 0, &session);
2910     if(FAILED(hr))
2911         return hr;
2912
2913     wrapper = AudioSessionWrapper_Create(NULL);
2914     if(!wrapper)
2915         return E_OUTOFMEMORY;
2916
2917     wrapper->session = session;
2918
2919     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2920
2921     return S_OK;
2922 }
2923
2924 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2925         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2926         ISimpleAudioVolume **out)
2927 {
2928     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2929     AudioSession *session;
2930     AudioSessionWrapper *wrapper;
2931     HRESULT hr;
2932
2933     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2934             flags, out);
2935
2936     hr = get_audio_session(session_guid, This->device, 0, &session);
2937     if(FAILED(hr))
2938         return hr;
2939
2940     wrapper = AudioSessionWrapper_Create(NULL);
2941     if(!wrapper)
2942         return E_OUTOFMEMORY;
2943
2944     wrapper->session = session;
2945
2946     *out = &wrapper->ISimpleAudioVolume_iface;
2947
2948     return S_OK;
2949 }
2950
2951 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2952         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2953 {
2954     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2955     FIXME("(%p)->(%p) - stub\n", This, out);
2956     return E_NOTIMPL;
2957 }
2958
2959 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2960         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2961 {
2962     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2963     FIXME("(%p)->(%p) - stub\n", This, notification);
2964     return E_NOTIMPL;
2965 }
2966
2967 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2968         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2969 {
2970     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2971     FIXME("(%p)->(%p) - stub\n", This, notification);
2972     return E_NOTIMPL;
2973 }
2974
2975 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2976         IAudioSessionManager2 *iface, const WCHAR *session_id,
2977         IAudioVolumeDuckNotification *notification)
2978 {
2979     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2980     FIXME("(%p)->(%p) - stub\n", This, notification);
2981     return E_NOTIMPL;
2982 }
2983
2984 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2985         IAudioSessionManager2 *iface,
2986         IAudioVolumeDuckNotification *notification)
2987 {
2988     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2989     FIXME("(%p)->(%p) - stub\n", This, notification);
2990     return E_NOTIMPL;
2991 }
2992
2993 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2994 {
2995     AudioSessionManager_QueryInterface,
2996     AudioSessionManager_AddRef,
2997     AudioSessionManager_Release,
2998     AudioSessionManager_GetAudioSessionControl,
2999     AudioSessionManager_GetSimpleAudioVolume,
3000     AudioSessionManager_GetSessionEnumerator,
3001     AudioSessionManager_RegisterSessionNotification,
3002     AudioSessionManager_UnregisterSessionNotification,
3003     AudioSessionManager_RegisterDuckNotification,
3004     AudioSessionManager_UnregisterDuckNotification
3005 };
3006
3007 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
3008         IAudioSessionManager2 **out)
3009 {
3010     SessionMgr *This;
3011
3012     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
3013     if(!This)
3014         return E_OUTOFMEMORY;
3015
3016     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
3017     This->device = device;
3018     This->ref = 1;
3019
3020     *out = &This->IAudioSessionManager2_iface;
3021
3022     return S_OK;
3023 }