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