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