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