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