crypt32: Add additional path for Solaris 11 Express.
[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     This->bufsize_frames = ceil(fmt->nSamplesPerSec * (duration / 10000000.));
823     This->local_buffer = HeapAlloc(GetProcessHeap(), 0,
824             This->bufsize_frames * fmt->nBlockAlign);
825     if(!This->local_buffer){
826         CoTaskMemFree(This->fmt);
827         This->fmt = NULL;
828         LeaveCriticalSection(&This->lock);
829         return E_OUTOFMEMORY;
830     }
831
832     This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
833     if(!This->vols){
834         CoTaskMemFree(This->fmt);
835         This->fmt = NULL;
836         LeaveCriticalSection(&This->lock);
837         return E_OUTOFMEMORY;
838     }
839
840     for(i = 0; i < fmt->nChannels; ++i)
841         This->vols[i] = 1.f;
842
843     This->share = mode;
844     This->flags = flags;
845
846     EnterCriticalSection(&g_sessions_lock);
847
848     hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
849             &This->session);
850     if(FAILED(hr)){
851         LeaveCriticalSection(&g_sessions_lock);
852         HeapFree(GetProcessHeap(), 0, This->vols);
853         This->vols = NULL;
854         CoTaskMemFree(This->fmt);
855         This->fmt = NULL;
856         LeaveCriticalSection(&This->lock);
857         return hr;
858     }
859
860     list_add_tail(&This->session->clients, &This->entry);
861
862     LeaveCriticalSection(&g_sessions_lock);
863
864     This->initted = TRUE;
865
866     oss_setvol(This, -1);
867
868     LeaveCriticalSection(&This->lock);
869
870     return S_OK;
871 }
872
873 static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface,
874         UINT32 *frames)
875 {
876     ACImpl *This = impl_from_IAudioClient(iface);
877
878     TRACE("(%p)->(%p)\n", This, frames);
879
880     if(!frames)
881         return E_POINTER;
882
883     EnterCriticalSection(&This->lock);
884
885     if(!This->initted){
886         LeaveCriticalSection(&This->lock);
887         return AUDCLNT_E_NOT_INITIALIZED;
888     }
889
890     *frames = This->bufsize_frames;
891
892     LeaveCriticalSection(&This->lock);
893
894     return S_OK;
895 }
896
897 static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface,
898         REFERENCE_TIME *latency)
899 {
900     ACImpl *This = impl_from_IAudioClient(iface);
901
902     TRACE("(%p)->(%p)\n", This, latency);
903
904     if(!latency)
905         return E_POINTER;
906
907     EnterCriticalSection(&This->lock);
908
909     if(!This->initted){
910         LeaveCriticalSection(&This->lock);
911         return AUDCLNT_E_NOT_INITIALIZED;
912     }
913
914     if(This->dataflow == eRender){
915         int delay_bytes;
916         double delay_s;
917
918         if(ioctl(This->fd, SNDCTL_DSP_GETODELAY, &delay_bytes) < 0){
919             LeaveCriticalSection(&This->lock);
920             WARN("GETODELAY failed: %d (%s)\n", errno, strerror(errno));
921             return E_FAIL;
922         }
923
924         delay_s = delay_bytes / (double)(This->fmt->nSamplesPerSec *
925                 This->fmt->nBlockAlign);
926
927         *latency = delay_s * 10000000;
928     }else
929         *latency = 10000; /* OSS doesn't provide input latency */
930
931     LeaveCriticalSection(&This->lock);
932
933     return S_OK;
934 }
935
936 static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface,
937         UINT32 *numpad)
938 {
939     ACImpl *This = impl_from_IAudioClient(iface);
940     audio_buf_info bi;
941
942     TRACE("(%p)->(%p)\n", This, numpad);
943
944     if(!numpad)
945         return E_POINTER;
946
947     EnterCriticalSection(&This->lock);
948
949     if(!This->initted){
950         LeaveCriticalSection(&This->lock);
951         return AUDCLNT_E_NOT_INITIALIZED;
952     }
953
954     if(This->dataflow == eRender){
955         if(ioctl(This->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){
956             LeaveCriticalSection(&This->lock);
957             WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno));
958             return E_FAIL;
959         }
960
961         *numpad = (bi.fragstotal * bi.fragsize - bi.bytes) /
962             This->fmt->nBlockAlign;
963
964         /* when the OSS buffer has less than one fragment of data, including
965          * no data, it often reports it as some non-zero portion of a
966          * fragment. when it has more than one fragment of data, it reports
967          * it as some multiple of that portion of the fragment size.
968          *
969          * so, we have to do some ugly workarounds to report the timing
970          * as accurately as possible */
971         if(*numpad < bi.fragsize / This->fmt->nBlockAlign){
972             *numpad = This->inbuf_frames;
973             This->inbuf_frames = 0;
974         }else{
975             if(*numpad < This->inbuf_frames)
976                 This->inbuf_frames = *numpad;
977             else
978                 *numpad = This->inbuf_frames;
979         }
980     }else if(This->dataflow == eCapture){
981         if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
982             LeaveCriticalSection(&This->lock);
983             WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
984             return E_FAIL;
985         }
986
987         if(bi.bytes <= bi.fragsize)
988             *numpad = 0;
989         else
990             *numpad = bi.bytes / This->fmt->nBlockAlign;
991     }else{
992         LeaveCriticalSection(&This->lock);
993         return E_UNEXPECTED;
994     }
995
996     *numpad += This->held_frames;
997
998     LeaveCriticalSection(&This->lock);
999
1000     return S_OK;
1001 }
1002
1003 static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
1004         AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx,
1005         WAVEFORMATEX **outpwfx)
1006 {
1007     ACImpl *This = impl_from_IAudioClient(iface);
1008     HRESULT ret;
1009
1010     TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx);
1011
1012     if(!pwfx || (mode == AUDCLNT_SHAREMODE_SHARED && !outpwfx))
1013         return E_POINTER;
1014
1015     if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
1016         return E_INVALIDARG;
1017
1018     if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1019             pwfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
1020         return E_INVALIDARG;
1021
1022     dump_fmt(pwfx);
1023
1024     EnterCriticalSection(&This->lock);
1025
1026     ret = setup_oss_device(This, pwfx, outpwfx);
1027
1028     LeaveCriticalSection(&This->lock);
1029
1030     return ret;
1031 }
1032
1033 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface,
1034         WAVEFORMATEX **pwfx)
1035 {
1036     ACImpl *This = impl_from_IAudioClient(iface);
1037     WAVEFORMATEXTENSIBLE *fmt;
1038     int formats;
1039
1040     TRACE("(%p)->(%p)\n", This, pwfx);
1041
1042     if(!pwfx)
1043         return E_POINTER;
1044     *pwfx = NULL;
1045
1046     if(This->dataflow == eRender)
1047         formats = This->ai.oformats;
1048     else if(This->dataflow == eCapture)
1049         formats = This->ai.iformats;
1050     else
1051         return E_UNEXPECTED;
1052
1053     fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE));
1054     if(!fmt)
1055         return E_OUTOFMEMORY;
1056
1057     fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1058     if(formats & AFMT_S16_LE){
1059         fmt->Format.wBitsPerSample = 16;
1060         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1061 #ifdef AFMT_FLOAT
1062     }else if(formats & AFMT_FLOAT){
1063         fmt->Format.wBitsPerSample = 32;
1064         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
1065 #endif
1066     }else if(formats & AFMT_U8){
1067         fmt->Format.wBitsPerSample = 8;
1068         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1069     }else if(formats & AFMT_S32_LE){
1070         fmt->Format.wBitsPerSample = 32;
1071         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1072     }else if(formats & AFMT_S24_LE){
1073         fmt->Format.wBitsPerSample = 24;
1074         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1075     }else{
1076         ERR("Didn't recognize any available OSS formats: %x\n", formats);
1077         CoTaskMemFree(fmt);
1078         return E_FAIL;
1079     }
1080
1081     fmt->Format.nChannels = This->ai.max_channels;
1082     fmt->Format.nSamplesPerSec = This->ai.max_rate;
1083     fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels);
1084
1085     fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample *
1086             fmt->Format.nChannels) / 8;
1087     fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec *
1088         fmt->Format.nBlockAlign;
1089
1090     fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample;
1091     fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1092
1093     *pwfx = (WAVEFORMATEX*)fmt;
1094     dump_fmt(*pwfx);
1095
1096     return S_OK;
1097 }
1098
1099 static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface,
1100         REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod)
1101 {
1102     ACImpl *This = impl_from_IAudioClient(iface);
1103
1104     TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod);
1105
1106     if(!defperiod && !minperiod)
1107         return E_POINTER;
1108
1109     EnterCriticalSection(&This->lock);
1110
1111     if(defperiod)
1112         *defperiod = DefaultPeriod;
1113     if(minperiod)
1114         *minperiod = MinimumPeriod;
1115
1116     LeaveCriticalSection(&This->lock);
1117
1118     return S_OK;
1119 }
1120
1121 static void oss_silence_buffer(ACImpl *This, BYTE *buf, UINT32 frames)
1122 {
1123     WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
1124     if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
1125             (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1126              IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
1127             This->fmt->wBitsPerSample == 8)
1128         memset(buf, 128, frames * This->fmt->nBlockAlign);
1129     else
1130         memset(buf, 0, frames * This->fmt->nBlockAlign);
1131 }
1132
1133 static void oss_write_data(ACImpl *This)
1134 {
1135     ssize_t written;
1136     UINT32 written_frames;
1137     size_t to_write;
1138     BYTE *buf =
1139         This->local_buffer + (This->lcl_offs_frames * This->fmt->nBlockAlign);
1140
1141     if(This->lcl_offs_frames + This->held_frames > This->bufsize_frames)
1142         to_write = This->bufsize_frames - This->lcl_offs_frames;
1143     else
1144         to_write = This->held_frames;
1145
1146     if(This->session->mute)
1147         oss_silence_buffer(This, buf, to_write);
1148
1149     written = write(This->fd, buf, to_write * This->fmt->nBlockAlign);
1150     if(written < 0){
1151         WARN("write failed: %d (%s)\n", errno, strerror(errno));
1152         return;
1153     }
1154     written_frames = written / This->fmt->nBlockAlign;
1155
1156     This->lcl_offs_frames += written_frames;
1157     This->lcl_offs_frames %= This->bufsize_frames;
1158     This->held_frames -= written_frames;
1159     This->inbuf_frames += written_frames;
1160
1161     if(written_frames < to_write){
1162         /* OSS buffer probably full */
1163         return;
1164     }
1165
1166     if(This->held_frames){
1167         /* wrapped and have some data back at the start to write */
1168
1169         if(This->session->mute)
1170             oss_silence_buffer(This, This->local_buffer, This->held_frames);
1171
1172         written = write(This->fd, This->local_buffer,
1173                 This->held_frames * This->fmt->nBlockAlign);
1174         if(written < 0){
1175             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1176             return;
1177         }
1178         written_frames = written / This->fmt->nBlockAlign;
1179
1180         This->lcl_offs_frames += written_frames;
1181         This->lcl_offs_frames %= This->bufsize_frames;
1182         This->held_frames -= written_frames;
1183         This->inbuf_frames += written_frames;
1184     }
1185 }
1186
1187 static void oss_read_data(ACImpl *This)
1188 {
1189     UINT64 pos, readable;
1190     audio_buf_info bi;
1191     ssize_t nread;
1192
1193     if(ioctl(This->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){
1194         WARN("GETISPACE failed: %d (%s)\n", errno, strerror(errno));
1195         return;
1196     }
1197
1198     pos = (This->held_frames + This->lcl_offs_frames) % This->bufsize_frames;
1199     readable = (This->bufsize_frames - pos) * This->fmt->nBlockAlign;
1200
1201     if(bi.bytes < readable)
1202         readable = bi.bytes;
1203
1204     nread = read(This->fd, This->local_buffer + pos * This->fmt->nBlockAlign,
1205             readable);
1206     if(nread < 0){
1207         WARN("read failed: %d (%s)\n", errno, strerror(errno));
1208         return;
1209     }
1210
1211     This->held_frames += nread / This->fmt->nBlockAlign;
1212
1213     if(This->held_frames > This->bufsize_frames){
1214         WARN("Overflow of unread data\n");
1215         This->lcl_offs_frames += This->held_frames;
1216         This->lcl_offs_frames %= This->bufsize_frames;
1217         This->held_frames = This->bufsize_frames;
1218     }
1219 }
1220
1221 static void CALLBACK oss_period_callback(void *user, BOOLEAN timer)
1222 {
1223     ACImpl *This = user;
1224
1225     EnterCriticalSection(&This->lock);
1226
1227     if(This->dataflow == eRender && This->held_frames)
1228         oss_write_data(This);
1229     else if(This->dataflow == eCapture)
1230         oss_read_data(This);
1231
1232     if(This->event)
1233         SetEvent(This->event);
1234
1235     LeaveCriticalSection(&This->lock);
1236 }
1237
1238 static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
1239 {
1240     ACImpl *This = impl_from_IAudioClient(iface);
1241     int mask;
1242
1243     TRACE("(%p)\n", This);
1244
1245     EnterCriticalSection(&This->lock);
1246
1247     if(!This->initted){
1248         LeaveCriticalSection(&This->lock);
1249         return AUDCLNT_E_NOT_INITIALIZED;
1250     }
1251
1252     if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
1253         LeaveCriticalSection(&This->lock);
1254         return AUDCLNT_E_EVENTHANDLE_NOT_SET;
1255     }
1256
1257     if(This->playing){
1258         LeaveCriticalSection(&This->lock);
1259         return AUDCLNT_E_NOT_STOPPED;
1260     }
1261
1262     if(This->dataflow == eRender)
1263         mask = PCM_ENABLE_OUTPUT;
1264     else if(This->dataflow == eCapture)
1265         mask = PCM_ENABLE_INPUT;
1266     else{
1267         LeaveCriticalSection(&This->lock);
1268         return E_UNEXPECTED;
1269     }
1270
1271     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1272         LeaveCriticalSection(&This->lock);
1273         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1274         return E_FAIL;
1275     }
1276
1277     if(!CreateTimerQueueTimer(&This->timer, g_timer_q,
1278                 oss_period_callback, This, 0, This->period_us / 1000,
1279                 WT_EXECUTEINTIMERTHREAD))
1280         ERR("Unable to create period timer: %u\n", GetLastError());
1281
1282     This->playing = TRUE;
1283
1284     LeaveCriticalSection(&This->lock);
1285
1286     return S_OK;
1287 }
1288
1289 static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
1290 {
1291     ACImpl *This = impl_from_IAudioClient(iface);
1292     int mask;
1293
1294     TRACE("(%p)\n", This);
1295
1296     EnterCriticalSection(&This->lock);
1297
1298     if(!This->initted){
1299         LeaveCriticalSection(&This->lock);
1300         return AUDCLNT_E_NOT_INITIALIZED;
1301     }
1302
1303     if(!This->playing){
1304         LeaveCriticalSection(&This->lock);
1305         return S_FALSE;
1306     }
1307
1308     if(This->timer && This->timer != INVALID_HANDLE_VALUE){
1309         DeleteTimerQueueTimer(g_timer_q, This->timer,
1310                 INVALID_HANDLE_VALUE);
1311         This->timer = NULL;
1312     }
1313
1314     if(ioctl(This->fd, SNDCTL_DSP_HALT, NULL) < 0){
1315         LeaveCriticalSection(&This->lock);
1316         WARN("HALT failed: %d (%s)\n", errno, strerror(errno));
1317         return E_FAIL;
1318     }
1319
1320     mask = 0;
1321     if(ioctl(This->fd, SNDCTL_DSP_SETTRIGGER, &mask) < 0){
1322         LeaveCriticalSection(&This->lock);
1323         WARN("SETTRIGGER failed: %d (%s)\n", errno, strerror(errno));
1324         return E_FAIL;
1325     }
1326
1327     This->playing = FALSE;
1328
1329     LeaveCriticalSection(&This->lock);
1330
1331     return S_OK;
1332 }
1333
1334 static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface)
1335 {
1336     ACImpl *This = impl_from_IAudioClient(iface);
1337
1338     TRACE("(%p)\n", This);
1339
1340     EnterCriticalSection(&This->lock);
1341
1342     if(!This->initted){
1343         LeaveCriticalSection(&This->lock);
1344         return AUDCLNT_E_NOT_INITIALIZED;
1345     }
1346
1347     if(This->playing){
1348         LeaveCriticalSection(&This->lock);
1349         return AUDCLNT_E_NOT_STOPPED;
1350     }
1351
1352     This->written_frames = 0;
1353     This->inbuf_frames = 0;
1354     This->held_frames = 0;
1355
1356     if(ioctl(This->fd, SNDCTL_DSP_SKIP, NULL) < 0)
1357         WARN("SKIP failed: %d (%s)\n", errno, strerror(errno));
1358
1359     LeaveCriticalSection(&This->lock);
1360
1361     return S_OK;
1362 }
1363
1364 static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface,
1365         HANDLE event)
1366 {
1367     ACImpl *This = impl_from_IAudioClient(iface);
1368
1369     TRACE("(%p)->(%p)\n", This, event);
1370
1371     if(!event)
1372         return E_INVALIDARG;
1373
1374     EnterCriticalSection(&This->lock);
1375
1376     if(!This->initted){
1377         LeaveCriticalSection(&This->lock);
1378         return AUDCLNT_E_NOT_INITIALIZED;
1379     }
1380
1381     if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
1382         LeaveCriticalSection(&This->lock);
1383         return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
1384     }
1385
1386     This->event = event;
1387
1388     LeaveCriticalSection(&This->lock);
1389
1390     return S_OK;
1391 }
1392
1393 static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
1394         void **ppv)
1395 {
1396     ACImpl *This = impl_from_IAudioClient(iface);
1397
1398     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
1399
1400     if(!ppv)
1401         return E_POINTER;
1402     *ppv = NULL;
1403
1404     EnterCriticalSection(&This->lock);
1405
1406     if(!This->initted){
1407         LeaveCriticalSection(&This->lock);
1408         return AUDCLNT_E_NOT_INITIALIZED;
1409     }
1410
1411     if(IsEqualIID(riid, &IID_IAudioRenderClient)){
1412         if(This->dataflow != eRender){
1413             LeaveCriticalSection(&This->lock);
1414             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1415         }
1416         IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
1417         *ppv = &This->IAudioRenderClient_iface;
1418     }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
1419         if(This->dataflow != eCapture){
1420             LeaveCriticalSection(&This->lock);
1421             return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
1422         }
1423         IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
1424         *ppv = &This->IAudioCaptureClient_iface;
1425     }else if(IsEqualIID(riid, &IID_IAudioClock)){
1426         IAudioClock_AddRef(&This->IAudioClock_iface);
1427         *ppv = &This->IAudioClock_iface;
1428     }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){
1429         IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface);
1430         *ppv = &This->IAudioStreamVolume_iface;
1431     }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){
1432         if(!This->session_wrapper){
1433             This->session_wrapper = AudioSessionWrapper_Create(This);
1434             if(!This->session_wrapper){
1435                 LeaveCriticalSection(&This->lock);
1436                 return E_OUTOFMEMORY;
1437             }
1438         }else
1439             IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
1440
1441         *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
1442     }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){
1443         if(!This->session_wrapper){
1444             This->session_wrapper = AudioSessionWrapper_Create(This);
1445             if(!This->session_wrapper){
1446                 LeaveCriticalSection(&This->lock);
1447                 return E_OUTOFMEMORY;
1448             }
1449         }else
1450             IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
1451
1452         *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
1453     }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){
1454         if(!This->session_wrapper){
1455             This->session_wrapper = AudioSessionWrapper_Create(This);
1456             if(!This->session_wrapper){
1457                 LeaveCriticalSection(&This->lock);
1458                 return E_OUTOFMEMORY;
1459             }
1460         }else
1461             ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
1462
1463         *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
1464     }
1465
1466     if(*ppv){
1467         LeaveCriticalSection(&This->lock);
1468         return S_OK;
1469     }
1470
1471     LeaveCriticalSection(&This->lock);
1472
1473     FIXME("stub %s\n", debugstr_guid(riid));
1474     return E_NOINTERFACE;
1475 }
1476
1477 static const IAudioClientVtbl AudioClient_Vtbl =
1478 {
1479     AudioClient_QueryInterface,
1480     AudioClient_AddRef,
1481     AudioClient_Release,
1482     AudioClient_Initialize,
1483     AudioClient_GetBufferSize,
1484     AudioClient_GetStreamLatency,
1485     AudioClient_GetCurrentPadding,
1486     AudioClient_IsFormatSupported,
1487     AudioClient_GetMixFormat,
1488     AudioClient_GetDevicePeriod,
1489     AudioClient_Start,
1490     AudioClient_Stop,
1491     AudioClient_Reset,
1492     AudioClient_SetEventHandle,
1493     AudioClient_GetService
1494 };
1495
1496 static HRESULT WINAPI AudioRenderClient_QueryInterface(
1497         IAudioRenderClient *iface, REFIID riid, void **ppv)
1498 {
1499     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1500
1501     if(!ppv)
1502         return E_POINTER;
1503     *ppv = NULL;
1504
1505     if(IsEqualIID(riid, &IID_IUnknown) ||
1506             IsEqualIID(riid, &IID_IAudioRenderClient))
1507         *ppv = iface;
1508     if(*ppv){
1509         IUnknown_AddRef((IUnknown*)*ppv);
1510         return S_OK;
1511     }
1512
1513     WARN("Unknown interface %s\n", debugstr_guid(riid));
1514     return E_NOINTERFACE;
1515 }
1516
1517 static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
1518 {
1519     ACImpl *This = impl_from_IAudioRenderClient(iface);
1520     return AudioClient_AddRef(&This->IAudioClient_iface);
1521 }
1522
1523 static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
1524 {
1525     ACImpl *This = impl_from_IAudioRenderClient(iface);
1526     return AudioClient_Release(&This->IAudioClient_iface);
1527 }
1528
1529 static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
1530         UINT32 frames, BYTE **data)
1531 {
1532     ACImpl *This = impl_from_IAudioRenderClient(iface);
1533     UINT32 pad, write_pos;
1534     HRESULT hr;
1535
1536     TRACE("(%p)->(%u, %p)\n", This, frames, data);
1537
1538     if(!data)
1539         return E_POINTER;
1540
1541     EnterCriticalSection(&This->lock);
1542
1543     if(This->buf_state != NOT_LOCKED){
1544         LeaveCriticalSection(&This->lock);
1545         return AUDCLNT_E_OUT_OF_ORDER;
1546     }
1547
1548     if(!frames){
1549         This->buf_state = LOCKED_NORMAL;
1550         LeaveCriticalSection(&This->lock);
1551         return S_OK;
1552     }
1553
1554     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1555     if(FAILED(hr)){
1556         LeaveCriticalSection(&This->lock);
1557         return hr;
1558     }
1559
1560     if(pad + frames > This->bufsize_frames){
1561         LeaveCriticalSection(&This->lock);
1562         return AUDCLNT_E_BUFFER_TOO_LARGE;
1563     }
1564
1565     write_pos =
1566         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1567     if(write_pos + frames > This->bufsize_frames){
1568         if(This->tmp_buffer_frames < frames){
1569             if(This->tmp_buffer)
1570                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1571                         This->tmp_buffer, frames * This->fmt->nBlockAlign);
1572             else
1573                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1574                         frames * This->fmt->nBlockAlign);
1575             if(!This->tmp_buffer){
1576                 LeaveCriticalSection(&This->lock);
1577                 return E_OUTOFMEMORY;
1578             }
1579             This->tmp_buffer_frames = frames;
1580         }
1581         *data = This->tmp_buffer;
1582         This->buf_state = LOCKED_WRAPPED;
1583     }else{
1584         *data = This->local_buffer +
1585             This->lcl_offs_frames * This->fmt->nBlockAlign;
1586         This->buf_state = LOCKED_NORMAL;
1587     }
1588
1589     LeaveCriticalSection(&This->lock);
1590
1591     return S_OK;
1592 }
1593
1594 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1595 {
1596     UINT32 write_offs_frames =
1597         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1598     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1599     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1600     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1601
1602     if(written_bytes < chunk_bytes){
1603         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1604     }else{
1605         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1606         memcpy(This->local_buffer, buffer + chunk_bytes,
1607                 written_bytes - chunk_bytes);
1608     }
1609 }
1610
1611 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1612         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1613 {
1614     ACImpl *This = impl_from_IAudioRenderClient(iface);
1615     BYTE *buffer;
1616     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1617
1618     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1619
1620     EnterCriticalSection(&This->lock);
1621
1622     if(This->buf_state == NOT_LOCKED || !written_frames){
1623         This->buf_state = NOT_LOCKED;
1624         LeaveCriticalSection(&This->lock);
1625         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1626     }
1627
1628     if(This->buf_state == LOCKED_NORMAL)
1629         buffer = This->local_buffer +
1630             This->lcl_offs_frames * This->fmt->nBlockAlign;
1631     else
1632         buffer = This->tmp_buffer;
1633
1634     if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1635         oss_silence_buffer(This, buffer, written_frames);
1636
1637     if(This->held_frames){
1638         if(This->buf_state == LOCKED_WRAPPED)
1639             oss_wrap_buffer(This, buffer, written_bytes);
1640
1641         This->held_frames += written_frames;
1642     }else{
1643         ssize_t w_bytes;
1644         UINT32 w_frames;
1645
1646         if(This->session->mute)
1647             oss_silence_buffer(This, buffer, written_frames);
1648
1649         w_bytes = write(This->fd, buffer,
1650                 written_frames * This->fmt->nBlockAlign);
1651         if(w_bytes < 0){
1652             LeaveCriticalSection(&This->lock);
1653             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1654             return E_FAIL;
1655         }
1656         w_frames = w_bytes / This->fmt->nBlockAlign;
1657         This->inbuf_frames += w_frames;
1658
1659         if(w_frames < written_frames){
1660             if(This->buf_state == LOCKED_WRAPPED)
1661                 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1662                         written_frames - w_frames);
1663
1664             This->held_frames = written_frames - w_frames;
1665         }
1666     }
1667
1668     This->written_frames += written_frames;
1669     This->buf_state = NOT_LOCKED;
1670
1671     LeaveCriticalSection(&This->lock);
1672
1673     return S_OK;
1674 }
1675
1676 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1677     AudioRenderClient_QueryInterface,
1678     AudioRenderClient_AddRef,
1679     AudioRenderClient_Release,
1680     AudioRenderClient_GetBuffer,
1681     AudioRenderClient_ReleaseBuffer
1682 };
1683
1684 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1685         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1686 {
1687     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1688
1689     if(!ppv)
1690         return E_POINTER;
1691     *ppv = NULL;
1692
1693     if(IsEqualIID(riid, &IID_IUnknown) ||
1694             IsEqualIID(riid, &IID_IAudioCaptureClient))
1695         *ppv = iface;
1696     if(*ppv){
1697         IUnknown_AddRef((IUnknown*)*ppv);
1698         return S_OK;
1699     }
1700
1701     WARN("Unknown interface %s\n", debugstr_guid(riid));
1702     return E_NOINTERFACE;
1703 }
1704
1705 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1706 {
1707     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1708     return IAudioClient_AddRef(&This->IAudioClient_iface);
1709 }
1710
1711 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1712 {
1713     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1714     return IAudioClient_Release(&This->IAudioClient_iface);
1715 }
1716
1717 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1718         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1719         UINT64 *qpcpos)
1720 {
1721     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1722     HRESULT hr;
1723
1724     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1725             devpos, qpcpos);
1726
1727     if(!data || !frames || !flags)
1728         return E_POINTER;
1729
1730     EnterCriticalSection(&This->lock);
1731
1732     if(This->buf_state != NOT_LOCKED){
1733         LeaveCriticalSection(&This->lock);
1734         return AUDCLNT_E_OUT_OF_ORDER;
1735     }
1736
1737     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1738     if(FAILED(hr)){
1739         LeaveCriticalSection(&This->lock);
1740         return hr;
1741     }
1742
1743     *flags = 0;
1744
1745     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1746         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1747         if(This->tmp_buffer_frames < *frames){
1748             if(This->tmp_buffer)
1749                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1750                         This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1751             else
1752                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1753                         *frames * This->fmt->nBlockAlign);
1754             if(!This->tmp_buffer){
1755                 LeaveCriticalSection(&This->lock);
1756                 return E_OUTOFMEMORY;
1757             }
1758             This->tmp_buffer_frames = *frames;
1759         }
1760
1761         *data = This->tmp_buffer;
1762         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1763             This->fmt->nBlockAlign;
1764         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1765         frames_bytes = *frames * This->fmt->nBlockAlign;
1766         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1767         memcpy(This->tmp_buffer, This->local_buffer,
1768                 frames_bytes - chunk_bytes);
1769     }else
1770         *data = This->local_buffer +
1771             This->lcl_offs_frames * This->fmt->nBlockAlign;
1772
1773     This->buf_state = LOCKED_NORMAL;
1774
1775     if(devpos || qpcpos)
1776         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1777
1778     LeaveCriticalSection(&This->lock);
1779
1780     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1781 }
1782
1783 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1784         IAudioCaptureClient *iface, UINT32 done)
1785 {
1786     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1787
1788     TRACE("(%p)->(%u)\n", This, done);
1789
1790     EnterCriticalSection(&This->lock);
1791
1792     if(This->buf_state == NOT_LOCKED){
1793         LeaveCriticalSection(&This->lock);
1794         return AUDCLNT_E_OUT_OF_ORDER;
1795     }
1796
1797     This->held_frames -= done;
1798     This->lcl_offs_frames += done;
1799     This->lcl_offs_frames %= This->bufsize_frames;
1800
1801     This->buf_state = NOT_LOCKED;
1802
1803     LeaveCriticalSection(&This->lock);
1804
1805     return S_OK;
1806 }
1807
1808 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1809         IAudioCaptureClient *iface, UINT32 *frames)
1810 {
1811     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1812
1813     TRACE("(%p)->(%p)\n", This, frames);
1814
1815     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1816 }
1817
1818 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1819 {
1820     AudioCaptureClient_QueryInterface,
1821     AudioCaptureClient_AddRef,
1822     AudioCaptureClient_Release,
1823     AudioCaptureClient_GetBuffer,
1824     AudioCaptureClient_ReleaseBuffer,
1825     AudioCaptureClient_GetNextPacketSize
1826 };
1827
1828 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1829         REFIID riid, void **ppv)
1830 {
1831     ACImpl *This = impl_from_IAudioClock(iface);
1832
1833     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1834
1835     if(!ppv)
1836         return E_POINTER;
1837     *ppv = NULL;
1838
1839     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1840         *ppv = iface;
1841     else if(IsEqualIID(riid, &IID_IAudioClock2))
1842         *ppv = &This->IAudioClock2_iface;
1843     if(*ppv){
1844         IUnknown_AddRef((IUnknown*)*ppv);
1845         return S_OK;
1846     }
1847
1848     WARN("Unknown interface %s\n", debugstr_guid(riid));
1849     return E_NOINTERFACE;
1850 }
1851
1852 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1853 {
1854     ACImpl *This = impl_from_IAudioClock(iface);
1855     return IAudioClient_AddRef(&This->IAudioClient_iface);
1856 }
1857
1858 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1859 {
1860     ACImpl *This = impl_from_IAudioClock(iface);
1861     return IAudioClient_Release(&This->IAudioClient_iface);
1862 }
1863
1864 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1865 {
1866     ACImpl *This = impl_from_IAudioClock(iface);
1867
1868     TRACE("(%p)->(%p)\n", This, freq);
1869
1870     *freq = This->fmt->nSamplesPerSec;
1871
1872     return S_OK;
1873 }
1874
1875 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1876         UINT64 *qpctime)
1877 {
1878     ACImpl *This = impl_from_IAudioClock(iface);
1879     UINT32 pad;
1880     HRESULT hr;
1881
1882     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1883
1884     if(!pos)
1885         return E_POINTER;
1886
1887     EnterCriticalSection(&This->lock);
1888
1889     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1890     if(FAILED(hr)){
1891         LeaveCriticalSection(&This->lock);
1892         return hr;
1893     }
1894
1895     if(This->dataflow == eRender)
1896         *pos = This->written_frames - pad;
1897     else if(This->dataflow == eCapture)
1898         *pos = This->written_frames + pad;
1899
1900     LeaveCriticalSection(&This->lock);
1901
1902     if(qpctime){
1903         LARGE_INTEGER stamp, freq;
1904         QueryPerformanceCounter(&stamp);
1905         QueryPerformanceFrequency(&freq);
1906         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1907     }
1908
1909     return S_OK;
1910 }
1911
1912 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1913         DWORD *chars)
1914 {
1915     ACImpl *This = impl_from_IAudioClock(iface);
1916
1917     TRACE("(%p)->(%p)\n", This, chars);
1918
1919     if(!chars)
1920         return E_POINTER;
1921
1922     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1923
1924     return S_OK;
1925 }
1926
1927 static const IAudioClockVtbl AudioClock_Vtbl =
1928 {
1929     AudioClock_QueryInterface,
1930     AudioClock_AddRef,
1931     AudioClock_Release,
1932     AudioClock_GetFrequency,
1933     AudioClock_GetPosition,
1934     AudioClock_GetCharacteristics
1935 };
1936
1937 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1938         REFIID riid, void **ppv)
1939 {
1940     ACImpl *This = impl_from_IAudioClock2(iface);
1941     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1942 }
1943
1944 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1945 {
1946     ACImpl *This = impl_from_IAudioClock2(iface);
1947     return IAudioClient_AddRef(&This->IAudioClient_iface);
1948 }
1949
1950 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1951 {
1952     ACImpl *This = impl_from_IAudioClock2(iface);
1953     return IAudioClient_Release(&This->IAudioClient_iface);
1954 }
1955
1956 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1957         UINT64 *pos, UINT64 *qpctime)
1958 {
1959     ACImpl *This = impl_from_IAudioClock2(iface);
1960
1961     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1962
1963     return E_NOTIMPL;
1964 }
1965
1966 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1967 {
1968     AudioClock2_QueryInterface,
1969     AudioClock2_AddRef,
1970     AudioClock2_Release,
1971     AudioClock2_GetDevicePosition
1972 };
1973
1974 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
1975 {
1976     AudioSessionWrapper *ret;
1977
1978     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1979             sizeof(AudioSessionWrapper));
1980     if(!ret)
1981         return NULL;
1982
1983     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
1984     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
1985     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
1986
1987     ret->ref = 1;
1988
1989     ret->client = client;
1990     if(client){
1991         ret->session = client->session;
1992         AudioClient_AddRef(&client->IAudioClient_iface);
1993     }
1994
1995     return ret;
1996 }
1997
1998 static HRESULT WINAPI AudioSessionControl_QueryInterface(
1999         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2000 {
2001     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2002
2003     if(!ppv)
2004         return E_POINTER;
2005     *ppv = NULL;
2006
2007     if(IsEqualIID(riid, &IID_IUnknown) ||
2008             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2009             IsEqualIID(riid, &IID_IAudioSessionControl2))
2010         *ppv = iface;
2011     if(*ppv){
2012         IUnknown_AddRef((IUnknown*)*ppv);
2013         return S_OK;
2014     }
2015
2016     WARN("Unknown interface %s\n", debugstr_guid(riid));
2017     return E_NOINTERFACE;
2018 }
2019
2020 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2021 {
2022     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2023     ULONG ref;
2024     ref = InterlockedIncrement(&This->ref);
2025     TRACE("(%p) Refcount now %u\n", This, ref);
2026     return ref;
2027 }
2028
2029 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2030 {
2031     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2032     ULONG ref;
2033     ref = InterlockedDecrement(&This->ref);
2034     TRACE("(%p) Refcount now %u\n", This, ref);
2035     if(!ref){
2036         if(This->client){
2037             EnterCriticalSection(&This->client->lock);
2038             This->client->session_wrapper = NULL;
2039             LeaveCriticalSection(&This->client->lock);
2040             AudioClient_Release(&This->client->IAudioClient_iface);
2041         }
2042         HeapFree(GetProcessHeap(), 0, This);
2043     }
2044     return ref;
2045 }
2046
2047 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2048         AudioSessionState *state)
2049 {
2050     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2051     ACImpl *client;
2052
2053     TRACE("(%p)->(%p)\n", This, state);
2054
2055     if(!state)
2056         return NULL_PTR_ERR;
2057
2058     EnterCriticalSection(&g_sessions_lock);
2059
2060     if(list_empty(&This->session->clients)){
2061         *state = AudioSessionStateExpired;
2062         LeaveCriticalSection(&g_sessions_lock);
2063         return S_OK;
2064     }
2065
2066     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2067         EnterCriticalSection(&client->lock);
2068         if(client->playing){
2069             *state = AudioSessionStateActive;
2070             LeaveCriticalSection(&client->lock);
2071             LeaveCriticalSection(&g_sessions_lock);
2072             return S_OK;
2073         }
2074         LeaveCriticalSection(&client->lock);
2075     }
2076
2077     LeaveCriticalSection(&g_sessions_lock);
2078
2079     *state = AudioSessionStateInactive;
2080
2081     return S_OK;
2082 }
2083
2084 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2085         IAudioSessionControl2 *iface, WCHAR **name)
2086 {
2087     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2088
2089     FIXME("(%p)->(%p) - stub\n", This, name);
2090
2091     return E_NOTIMPL;
2092 }
2093
2094 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2095         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2096 {
2097     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2098
2099     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2100
2101     return E_NOTIMPL;
2102 }
2103
2104 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2105         IAudioSessionControl2 *iface, WCHAR **path)
2106 {
2107     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2108
2109     FIXME("(%p)->(%p) - stub\n", This, path);
2110
2111     return E_NOTIMPL;
2112 }
2113
2114 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2115         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2116 {
2117     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2118
2119     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2120
2121     return E_NOTIMPL;
2122 }
2123
2124 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2125         IAudioSessionControl2 *iface, GUID *group)
2126 {
2127     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2128
2129     FIXME("(%p)->(%p) - stub\n", This, group);
2130
2131     return E_NOTIMPL;
2132 }
2133
2134 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2135         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2136 {
2137     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2138
2139     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2140             debugstr_guid(session));
2141
2142     return E_NOTIMPL;
2143 }
2144
2145 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2146         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2147 {
2148     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2149
2150     FIXME("(%p)->(%p) - stub\n", This, events);
2151
2152     return S_OK;
2153 }
2154
2155 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2156         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2157 {
2158     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2159
2160     FIXME("(%p)->(%p) - stub\n", This, events);
2161
2162     return S_OK;
2163 }
2164
2165 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2166         IAudioSessionControl2 *iface, WCHAR **id)
2167 {
2168     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2169
2170     FIXME("(%p)->(%p) - stub\n", This, id);
2171
2172     return E_NOTIMPL;
2173 }
2174
2175 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2176         IAudioSessionControl2 *iface, WCHAR **id)
2177 {
2178     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2179
2180     FIXME("(%p)->(%p) - stub\n", This, id);
2181
2182     return E_NOTIMPL;
2183 }
2184
2185 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2186         IAudioSessionControl2 *iface, DWORD *pid)
2187 {
2188     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2189
2190     TRACE("(%p)->(%p)\n", This, pid);
2191
2192     if(!pid)
2193         return E_POINTER;
2194
2195     *pid = GetCurrentProcessId();
2196
2197     return S_OK;
2198 }
2199
2200 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2201         IAudioSessionControl2 *iface)
2202 {
2203     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2204
2205     TRACE("(%p)\n", This);
2206
2207     return S_FALSE;
2208 }
2209
2210 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2211         IAudioSessionControl2 *iface, BOOL optout)
2212 {
2213     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2214
2215     TRACE("(%p)->(%d)\n", This, optout);
2216
2217     return S_OK;
2218 }
2219
2220 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2221 {
2222     AudioSessionControl_QueryInterface,
2223     AudioSessionControl_AddRef,
2224     AudioSessionControl_Release,
2225     AudioSessionControl_GetState,
2226     AudioSessionControl_GetDisplayName,
2227     AudioSessionControl_SetDisplayName,
2228     AudioSessionControl_GetIconPath,
2229     AudioSessionControl_SetIconPath,
2230     AudioSessionControl_GetGroupingParam,
2231     AudioSessionControl_SetGroupingParam,
2232     AudioSessionControl_RegisterAudioSessionNotification,
2233     AudioSessionControl_UnregisterAudioSessionNotification,
2234     AudioSessionControl_GetSessionIdentifier,
2235     AudioSessionControl_GetSessionInstanceIdentifier,
2236     AudioSessionControl_GetProcessId,
2237     AudioSessionControl_IsSystemSoundsSession,
2238     AudioSessionControl_SetDuckingPreference
2239 };
2240
2241 /* index == -1 means set all channels, otherwise sets only the given channel */
2242 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2243 {
2244     int setreq, getreq;
2245     unsigned int vol;
2246     unsigned short l;
2247     float level;
2248
2249     if(index == (UINT32)-1){
2250         HRESULT ret = S_OK;
2251         UINT32 i;
2252         for(i = 0; i < This->fmt->nChannels; ++i){
2253             HRESULT hr;
2254             hr = oss_setvol(This, i);
2255             if(FAILED(hr))
2256                 ret = hr;
2257         }
2258         return ret;
2259     }
2260
2261     if(index > 1)
2262         /* OSS doesn't support volume control past the first two channels */
2263         return S_OK;
2264
2265     if(This->dataflow == eRender){
2266         setreq = SNDCTL_DSP_SETPLAYVOL;
2267         getreq = SNDCTL_DSP_GETPLAYVOL;
2268     }else if(This->dataflow == eCapture){
2269         setreq = SNDCTL_DSP_SETRECVOL;
2270         getreq = SNDCTL_DSP_GETRECVOL;
2271     }else
2272         return E_UNEXPECTED;
2273
2274     if(ioctl(This->fd, getreq, &vol) < 0){
2275         if(errno == EINVAL)
2276             /* device doesn't support this call */
2277             return S_OK;
2278
2279         WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2280         return E_FAIL;
2281     }
2282
2283     level = This->session->master_vol * This->session->channel_vols[index] *
2284         This->vols[index];
2285     l = level * 100;
2286     if(index == 0)
2287         vol = l | (vol & 0xFF00);
2288     else
2289         vol = (vol & 0xFF) | (l << 8);
2290
2291     if(ioctl(This->fd, setreq, &vol) < 0){
2292         if(errno == EINVAL)
2293             /* device doesn't support this call */
2294             return S_OK;
2295
2296         WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2297         return E_FAIL;
2298     }
2299
2300     return S_OK;
2301 }
2302
2303 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2304 {
2305     HRESULT ret = S_OK;
2306     ACImpl *client;
2307
2308     LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2309         HRESULT hr;
2310         hr = oss_setvol(client, index);
2311         if(FAILED(hr))
2312             ret = hr;
2313     }
2314
2315     return ret;
2316 }
2317
2318 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2319         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2320 {
2321     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2322
2323     if(!ppv)
2324         return E_POINTER;
2325     *ppv = NULL;
2326
2327     if(IsEqualIID(riid, &IID_IUnknown) ||
2328             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2329         *ppv = iface;
2330     if(*ppv){
2331         IUnknown_AddRef((IUnknown*)*ppv);
2332         return S_OK;
2333     }
2334
2335     WARN("Unknown interface %s\n", debugstr_guid(riid));
2336     return E_NOINTERFACE;
2337 }
2338
2339 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2340 {
2341     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2342     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2343 }
2344
2345 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2346 {
2347     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2348     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2349 }
2350
2351 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2352         ISimpleAudioVolume *iface, float level, const GUID *context)
2353 {
2354     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2355     AudioSession *session = This->session;
2356     HRESULT ret;
2357
2358     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2359
2360     if(level < 0.f || level > 1.f)
2361         return E_INVALIDARG;
2362
2363     if(context)
2364         FIXME("Notifications not supported yet\n");
2365
2366     EnterCriticalSection(&session->lock);
2367
2368     session->master_vol = level;
2369
2370     ret = oss_session_setvol(session, -1);
2371
2372     LeaveCriticalSection(&session->lock);
2373
2374     return ret;
2375 }
2376
2377 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2378         ISimpleAudioVolume *iface, float *level)
2379 {
2380     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2381     AudioSession *session = This->session;
2382
2383     TRACE("(%p)->(%p)\n", session, level);
2384
2385     if(!level)
2386         return NULL_PTR_ERR;
2387
2388     *level = session->master_vol;
2389
2390     return S_OK;
2391 }
2392
2393 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2394         BOOL mute, const GUID *context)
2395 {
2396     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2397     AudioSession *session = This->session;
2398
2399     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2400
2401     EnterCriticalSection(&session->lock);
2402
2403     if(!mute && session->mute){
2404         ACImpl *client;
2405
2406         session->mute = mute;
2407
2408         LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2409             EnterCriticalSection(&client->lock);
2410             if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2411                 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2412                         strerror(errno));
2413             oss_write_data(client);
2414             LeaveCriticalSection(&client->lock);
2415         }
2416     }else
2417         session->mute = mute;
2418
2419     LeaveCriticalSection(&session->lock);
2420
2421     return S_OK;
2422 }
2423
2424 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2425         BOOL *mute)
2426 {
2427     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2428     AudioSession *session = This->session;
2429
2430     TRACE("(%p)->(%p)\n", session, mute);
2431
2432     if(!mute)
2433         return NULL_PTR_ERR;
2434
2435     *mute = This->session->mute;
2436
2437     return S_OK;
2438 }
2439
2440 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2441 {
2442     SimpleAudioVolume_QueryInterface,
2443     SimpleAudioVolume_AddRef,
2444     SimpleAudioVolume_Release,
2445     SimpleAudioVolume_SetMasterVolume,
2446     SimpleAudioVolume_GetMasterVolume,
2447     SimpleAudioVolume_SetMute,
2448     SimpleAudioVolume_GetMute
2449 };
2450
2451 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2452         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2453 {
2454     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2455
2456     if(!ppv)
2457         return E_POINTER;
2458     *ppv = NULL;
2459
2460     if(IsEqualIID(riid, &IID_IUnknown) ||
2461             IsEqualIID(riid, &IID_IAudioStreamVolume))
2462         *ppv = iface;
2463     if(*ppv){
2464         IUnknown_AddRef((IUnknown*)*ppv);
2465         return S_OK;
2466     }
2467
2468     WARN("Unknown interface %s\n", debugstr_guid(riid));
2469     return E_NOINTERFACE;
2470 }
2471
2472 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2473 {
2474     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2475     return IAudioClient_AddRef(&This->IAudioClient_iface);
2476 }
2477
2478 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2479 {
2480     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2481     return IAudioClient_Release(&This->IAudioClient_iface);
2482 }
2483
2484 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2485         IAudioStreamVolume *iface, UINT32 *out)
2486 {
2487     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2488
2489     TRACE("(%p)->(%p)\n", This, out);
2490
2491     if(!out)
2492         return E_POINTER;
2493
2494     *out = This->fmt->nChannels;
2495
2496     return S_OK;
2497 }
2498
2499 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2500         IAudioStreamVolume *iface, UINT32 index, float level)
2501 {
2502     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2503     HRESULT ret;
2504
2505     TRACE("(%p)->(%d, %f)\n", This, index, level);
2506
2507     if(level < 0.f || level > 1.f)
2508         return E_INVALIDARG;
2509
2510     if(index >= This->fmt->nChannels)
2511         return E_INVALIDARG;
2512
2513     EnterCriticalSection(&This->lock);
2514
2515     This->vols[index] = level;
2516
2517     ret = oss_setvol(This, index);
2518
2519     LeaveCriticalSection(&This->lock);
2520
2521     return ret;
2522 }
2523
2524 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2525         IAudioStreamVolume *iface, UINT32 index, float *level)
2526 {
2527     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2528
2529     TRACE("(%p)->(%d, %p)\n", This, index, level);
2530
2531     if(!level)
2532         return E_POINTER;
2533
2534     if(index >= This->fmt->nChannels)
2535         return E_INVALIDARG;
2536
2537     *level = This->vols[index];
2538
2539     return S_OK;
2540 }
2541
2542 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2543         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2544 {
2545     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2546     int i;
2547     HRESULT ret;
2548
2549     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2550
2551     if(!levels)
2552         return E_POINTER;
2553
2554     if(count != This->fmt->nChannels)
2555         return E_INVALIDARG;
2556
2557     EnterCriticalSection(&This->lock);
2558
2559     for(i = 0; i < count; ++i)
2560         This->vols[i] = levels[i];
2561
2562     ret = oss_setvol(This, -1);
2563
2564     LeaveCriticalSection(&This->lock);
2565
2566     return ret;
2567 }
2568
2569 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2570         IAudioStreamVolume *iface, UINT32 count, float *levels)
2571 {
2572     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2573     int i;
2574
2575     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2576
2577     if(!levels)
2578         return E_POINTER;
2579
2580     if(count != This->fmt->nChannels)
2581         return E_INVALIDARG;
2582
2583     EnterCriticalSection(&This->lock);
2584
2585     for(i = 0; i < count; ++i)
2586         levels[i] = This->vols[i];
2587
2588     LeaveCriticalSection(&This->lock);
2589
2590     return S_OK;
2591 }
2592
2593 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2594 {
2595     AudioStreamVolume_QueryInterface,
2596     AudioStreamVolume_AddRef,
2597     AudioStreamVolume_Release,
2598     AudioStreamVolume_GetChannelCount,
2599     AudioStreamVolume_SetChannelVolume,
2600     AudioStreamVolume_GetChannelVolume,
2601     AudioStreamVolume_SetAllVolumes,
2602     AudioStreamVolume_GetAllVolumes
2603 };
2604
2605 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2606         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2607 {
2608     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2609
2610     if(!ppv)
2611         return E_POINTER;
2612     *ppv = NULL;
2613
2614     if(IsEqualIID(riid, &IID_IUnknown) ||
2615             IsEqualIID(riid, &IID_IChannelAudioVolume))
2616         *ppv = iface;
2617     if(*ppv){
2618         IUnknown_AddRef((IUnknown*)*ppv);
2619         return S_OK;
2620     }
2621
2622     WARN("Unknown interface %s\n", debugstr_guid(riid));
2623     return E_NOINTERFACE;
2624 }
2625
2626 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2627 {
2628     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2629     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2630 }
2631
2632 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2633 {
2634     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2635     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2636 }
2637
2638 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2639         IChannelAudioVolume *iface, UINT32 *out)
2640 {
2641     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2642     AudioSession *session = This->session;
2643
2644     TRACE("(%p)->(%p)\n", session, out);
2645
2646     if(!out)
2647         return NULL_PTR_ERR;
2648
2649     *out = session->channel_count;
2650
2651     return S_OK;
2652 }
2653
2654 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2655         IChannelAudioVolume *iface, UINT32 index, float level,
2656         const GUID *context)
2657 {
2658     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2659     AudioSession *session = This->session;
2660     HRESULT ret;
2661
2662     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2663             wine_dbgstr_guid(context));
2664
2665     if(level < 0.f || level > 1.f)
2666         return E_INVALIDARG;
2667
2668     if(index >= session->channel_count)
2669         return E_INVALIDARG;
2670
2671     if(context)
2672         FIXME("Notifications not supported yet\n");
2673
2674     EnterCriticalSection(&session->lock);
2675
2676     session->channel_vols[index] = level;
2677
2678     ret = oss_session_setvol(session, index);
2679
2680     LeaveCriticalSection(&session->lock);
2681
2682     return ret;
2683 }
2684
2685 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2686         IChannelAudioVolume *iface, UINT32 index, float *level)
2687 {
2688     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2689     AudioSession *session = This->session;
2690
2691     TRACE("(%p)->(%d, %p)\n", session, index, level);
2692
2693     if(!level)
2694         return NULL_PTR_ERR;
2695
2696     if(index >= session->channel_count)
2697         return E_INVALIDARG;
2698
2699     *level = session->channel_vols[index];
2700
2701     return S_OK;
2702 }
2703
2704 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2705         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2706         const GUID *context)
2707 {
2708     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2709     AudioSession *session = This->session;
2710     int i;
2711     HRESULT ret;
2712
2713     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2714             wine_dbgstr_guid(context));
2715
2716     if(!levels)
2717         return NULL_PTR_ERR;
2718
2719     if(count != session->channel_count)
2720         return E_INVALIDARG;
2721
2722     if(context)
2723         FIXME("Notifications not supported yet\n");
2724
2725     EnterCriticalSection(&session->lock);
2726
2727     for(i = 0; i < count; ++i)
2728         session->channel_vols[i] = levels[i];
2729
2730     ret = oss_session_setvol(session, -1);
2731
2732     LeaveCriticalSection(&session->lock);
2733
2734     return ret;
2735 }
2736
2737 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2738         IChannelAudioVolume *iface, UINT32 count, float *levels)
2739 {
2740     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2741     AudioSession *session = This->session;
2742     int i;
2743
2744     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2745
2746     if(!levels)
2747         return NULL_PTR_ERR;
2748
2749     if(count != session->channel_count)
2750         return E_INVALIDARG;
2751
2752     for(i = 0; i < count; ++i)
2753         levels[i] = session->channel_vols[i];
2754
2755     return S_OK;
2756 }
2757
2758 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2759 {
2760     ChannelAudioVolume_QueryInterface,
2761     ChannelAudioVolume_AddRef,
2762     ChannelAudioVolume_Release,
2763     ChannelAudioVolume_GetChannelCount,
2764     ChannelAudioVolume_SetChannelVolume,
2765     ChannelAudioVolume_GetChannelVolume,
2766     ChannelAudioVolume_SetAllVolumes,
2767     ChannelAudioVolume_GetAllVolumes
2768 };
2769
2770 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2771         REFIID riid, void **ppv)
2772 {
2773     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2774
2775     if(!ppv)
2776         return E_POINTER;
2777     *ppv = NULL;
2778
2779     if(IsEqualIID(riid, &IID_IUnknown) ||
2780             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2781             IsEqualIID(riid, &IID_IAudioSessionManager2))
2782         *ppv = iface;
2783     if(*ppv){
2784         IUnknown_AddRef((IUnknown*)*ppv);
2785         return S_OK;
2786     }
2787
2788     WARN("Unknown interface %s\n", debugstr_guid(riid));
2789     return E_NOINTERFACE;
2790 }
2791
2792 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2793 {
2794     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2795     ULONG ref;
2796     ref = InterlockedIncrement(&This->ref);
2797     TRACE("(%p) Refcount now %u\n", This, ref);
2798     return ref;
2799 }
2800
2801 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2802 {
2803     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2804     ULONG ref;
2805     ref = InterlockedDecrement(&This->ref);
2806     TRACE("(%p) Refcount now %u\n", This, ref);
2807     if(!ref)
2808         HeapFree(GetProcessHeap(), 0, This);
2809     return ref;
2810 }
2811
2812 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2813         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2814         IAudioSessionControl **out)
2815 {
2816     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2817     AudioSession *session;
2818     AudioSessionWrapper *wrapper;
2819     HRESULT hr;
2820
2821     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2822             flags, out);
2823
2824     hr = get_audio_session(session_guid, This->device, 0, &session);
2825     if(FAILED(hr))
2826         return hr;
2827
2828     wrapper = AudioSessionWrapper_Create(NULL);
2829     if(!wrapper)
2830         return E_OUTOFMEMORY;
2831
2832     wrapper->session = session;
2833
2834     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2835
2836     return S_OK;
2837 }
2838
2839 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2840         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2841         ISimpleAudioVolume **out)
2842 {
2843     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2844     AudioSession *session;
2845     AudioSessionWrapper *wrapper;
2846     HRESULT hr;
2847
2848     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2849             flags, out);
2850
2851     hr = get_audio_session(session_guid, This->device, 0, &session);
2852     if(FAILED(hr))
2853         return hr;
2854
2855     wrapper = AudioSessionWrapper_Create(NULL);
2856     if(!wrapper)
2857         return E_OUTOFMEMORY;
2858
2859     wrapper->session = session;
2860
2861     *out = &wrapper->ISimpleAudioVolume_iface;
2862
2863     return S_OK;
2864 }
2865
2866 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2867         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2868 {
2869     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2870     FIXME("(%p)->(%p) - stub\n", This, out);
2871     return E_NOTIMPL;
2872 }
2873
2874 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2875         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2876 {
2877     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2878     FIXME("(%p)->(%p) - stub\n", This, notification);
2879     return E_NOTIMPL;
2880 }
2881
2882 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2883         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2884 {
2885     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2886     FIXME("(%p)->(%p) - stub\n", This, notification);
2887     return E_NOTIMPL;
2888 }
2889
2890 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2891         IAudioSessionManager2 *iface, const WCHAR *session_id,
2892         IAudioVolumeDuckNotification *notification)
2893 {
2894     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2895     FIXME("(%p)->(%p) - stub\n", This, notification);
2896     return E_NOTIMPL;
2897 }
2898
2899 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2900         IAudioSessionManager2 *iface,
2901         IAudioVolumeDuckNotification *notification)
2902 {
2903     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2904     FIXME("(%p)->(%p) - stub\n", This, notification);
2905     return E_NOTIMPL;
2906 }
2907
2908 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2909 {
2910     AudioSessionManager_QueryInterface,
2911     AudioSessionManager_AddRef,
2912     AudioSessionManager_Release,
2913     AudioSessionManager_GetAudioSessionControl,
2914     AudioSessionManager_GetSimpleAudioVolume,
2915     AudioSessionManager_GetSessionEnumerator,
2916     AudioSessionManager_RegisterSessionNotification,
2917     AudioSessionManager_UnregisterSessionNotification,
2918     AudioSessionManager_RegisterDuckNotification,
2919     AudioSessionManager_UnregisterDuckNotification
2920 };
2921
2922 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2923         IAudioSessionManager2 **out)
2924 {
2925     SessionMgr *This;
2926
2927     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2928     if(!This)
2929         return E_OUTOFMEMORY;
2930
2931     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2932     This->device = device;
2933     This->ref = 1;
2934
2935     *out = &This->IAudioSessionManager2_iface;
2936
2937     return S_OK;
2938 }