wineoss.drv: Print strerror of errno, not of -1 (Coverity).
[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 +
1615             This->lcl_offs_frames * This->fmt->nBlockAlign;
1616         This->buf_state = LOCKED_NORMAL;
1617     }
1618
1619     LeaveCriticalSection(&This->lock);
1620
1621     return S_OK;
1622 }
1623
1624 static void oss_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes)
1625 {
1626     UINT32 write_offs_frames =
1627         (This->lcl_offs_frames + This->held_frames) % This->bufsize_frames;
1628     UINT32 write_offs_bytes = write_offs_frames * This->fmt->nBlockAlign;
1629     UINT32 chunk_frames = This->bufsize_frames - write_offs_frames;
1630     UINT32 chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
1631
1632     if(written_bytes < chunk_bytes){
1633         memcpy(This->local_buffer + write_offs_bytes, buffer, written_bytes);
1634     }else{
1635         memcpy(This->local_buffer + write_offs_bytes, buffer, chunk_bytes);
1636         memcpy(This->local_buffer, buffer + chunk_bytes,
1637                 written_bytes - chunk_bytes);
1638     }
1639 }
1640
1641 static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
1642         IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
1643 {
1644     ACImpl *This = impl_from_IAudioRenderClient(iface);
1645     BYTE *buffer;
1646     UINT32 written_bytes = written_frames * This->fmt->nBlockAlign;
1647
1648     TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
1649
1650     EnterCriticalSection(&This->lock);
1651
1652     if(This->buf_state == NOT_LOCKED || !written_frames){
1653         This->buf_state = NOT_LOCKED;
1654         LeaveCriticalSection(&This->lock);
1655         return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
1656     }
1657
1658     if(This->buf_state == LOCKED_NORMAL)
1659         buffer = This->local_buffer +
1660             This->lcl_offs_frames * This->fmt->nBlockAlign;
1661     else
1662         buffer = This->tmp_buffer;
1663
1664     if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
1665         oss_silence_buffer(This, buffer, written_frames);
1666
1667     if(This->held_frames){
1668         if(This->buf_state == LOCKED_WRAPPED)
1669             oss_wrap_buffer(This, buffer, written_bytes);
1670
1671         This->held_frames += written_frames;
1672     }else{
1673         ssize_t w_bytes;
1674         UINT32 w_frames;
1675
1676         if(This->session->mute)
1677             oss_silence_buffer(This, buffer, written_frames);
1678
1679         w_bytes = write(This->fd, buffer,
1680                 written_frames * This->fmt->nBlockAlign);
1681         if(w_bytes < 0){
1682             LeaveCriticalSection(&This->lock);
1683             WARN("write failed: %d (%s)\n", errno, strerror(errno));
1684             return E_FAIL;
1685         }
1686         w_frames = w_bytes / This->fmt->nBlockAlign;
1687         This->inbuf_frames += w_frames;
1688
1689         if(w_frames < written_frames){
1690             if(This->buf_state == LOCKED_WRAPPED)
1691                 oss_wrap_buffer(This, This->tmp_buffer + w_bytes,
1692                         written_frames - w_frames);
1693
1694             This->held_frames = written_frames - w_frames;
1695         }
1696     }
1697
1698     This->written_frames += written_frames;
1699     This->buf_state = NOT_LOCKED;
1700
1701     LeaveCriticalSection(&This->lock);
1702
1703     return S_OK;
1704 }
1705
1706 static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
1707     AudioRenderClient_QueryInterface,
1708     AudioRenderClient_AddRef,
1709     AudioRenderClient_Release,
1710     AudioRenderClient_GetBuffer,
1711     AudioRenderClient_ReleaseBuffer
1712 };
1713
1714 static HRESULT WINAPI AudioCaptureClient_QueryInterface(
1715         IAudioCaptureClient *iface, REFIID riid, void **ppv)
1716 {
1717     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1718
1719     if(!ppv)
1720         return E_POINTER;
1721     *ppv = NULL;
1722
1723     if(IsEqualIID(riid, &IID_IUnknown) ||
1724             IsEqualIID(riid, &IID_IAudioCaptureClient))
1725         *ppv = iface;
1726     if(*ppv){
1727         IUnknown_AddRef((IUnknown*)*ppv);
1728         return S_OK;
1729     }
1730
1731     WARN("Unknown interface %s\n", debugstr_guid(riid));
1732     return E_NOINTERFACE;
1733 }
1734
1735 static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
1736 {
1737     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1738     return IAudioClient_AddRef(&This->IAudioClient_iface);
1739 }
1740
1741 static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
1742 {
1743     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1744     return IAudioClient_Release(&This->IAudioClient_iface);
1745 }
1746
1747 static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
1748         BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
1749         UINT64 *qpcpos)
1750 {
1751     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1752     HRESULT hr;
1753
1754     TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
1755             devpos, qpcpos);
1756
1757     if(!data || !frames || !flags)
1758         return E_POINTER;
1759
1760     EnterCriticalSection(&This->lock);
1761
1762     if(This->buf_state != NOT_LOCKED){
1763         LeaveCriticalSection(&This->lock);
1764         return AUDCLNT_E_OUT_OF_ORDER;
1765     }
1766
1767     hr = IAudioCaptureClient_GetNextPacketSize(iface, frames);
1768     if(FAILED(hr)){
1769         LeaveCriticalSection(&This->lock);
1770         return hr;
1771     }
1772
1773     *flags = 0;
1774
1775     if(This->lcl_offs_frames + *frames > This->bufsize_frames){
1776         UINT32 chunk_bytes, offs_bytes, frames_bytes;
1777         if(This->tmp_buffer_frames < *frames){
1778             if(This->tmp_buffer)
1779                 This->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0,
1780                         This->tmp_buffer, *frames * This->fmt->nBlockAlign);
1781             else
1782                 This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0,
1783                         *frames * This->fmt->nBlockAlign);
1784             if(!This->tmp_buffer){
1785                 LeaveCriticalSection(&This->lock);
1786                 return E_OUTOFMEMORY;
1787             }
1788             This->tmp_buffer_frames = *frames;
1789         }
1790
1791         *data = This->tmp_buffer;
1792         chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) *
1793             This->fmt->nBlockAlign;
1794         offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
1795         frames_bytes = *frames * This->fmt->nBlockAlign;
1796         memcpy(This->tmp_buffer, This->local_buffer + offs_bytes, chunk_bytes);
1797         memcpy(This->tmp_buffer, This->local_buffer,
1798                 frames_bytes - chunk_bytes);
1799     }else
1800         *data = This->local_buffer +
1801             This->lcl_offs_frames * This->fmt->nBlockAlign;
1802
1803     This->buf_state = LOCKED_NORMAL;
1804
1805     if(devpos || qpcpos)
1806         IAudioClock_GetPosition(&This->IAudioClock_iface, devpos, qpcpos);
1807
1808     LeaveCriticalSection(&This->lock);
1809
1810     return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
1811 }
1812
1813 static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
1814         IAudioCaptureClient *iface, UINT32 done)
1815 {
1816     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1817
1818     TRACE("(%p)->(%u)\n", This, done);
1819
1820     EnterCriticalSection(&This->lock);
1821
1822     if(This->buf_state == NOT_LOCKED){
1823         LeaveCriticalSection(&This->lock);
1824         return AUDCLNT_E_OUT_OF_ORDER;
1825     }
1826
1827     This->held_frames -= done;
1828     This->lcl_offs_frames += done;
1829     This->lcl_offs_frames %= This->bufsize_frames;
1830
1831     This->buf_state = NOT_LOCKED;
1832
1833     LeaveCriticalSection(&This->lock);
1834
1835     return S_OK;
1836 }
1837
1838 static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
1839         IAudioCaptureClient *iface, UINT32 *frames)
1840 {
1841     ACImpl *This = impl_from_IAudioCaptureClient(iface);
1842
1843     TRACE("(%p)->(%p)\n", This, frames);
1844
1845     return AudioClient_GetCurrentPadding(&This->IAudioClient_iface, frames);
1846 }
1847
1848 static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
1849 {
1850     AudioCaptureClient_QueryInterface,
1851     AudioCaptureClient_AddRef,
1852     AudioCaptureClient_Release,
1853     AudioCaptureClient_GetBuffer,
1854     AudioCaptureClient_ReleaseBuffer,
1855     AudioCaptureClient_GetNextPacketSize
1856 };
1857
1858 static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
1859         REFIID riid, void **ppv)
1860 {
1861     ACImpl *This = impl_from_IAudioClock(iface);
1862
1863     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
1864
1865     if(!ppv)
1866         return E_POINTER;
1867     *ppv = NULL;
1868
1869     if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
1870         *ppv = iface;
1871     else if(IsEqualIID(riid, &IID_IAudioClock2))
1872         *ppv = &This->IAudioClock2_iface;
1873     if(*ppv){
1874         IUnknown_AddRef((IUnknown*)*ppv);
1875         return S_OK;
1876     }
1877
1878     WARN("Unknown interface %s\n", debugstr_guid(riid));
1879     return E_NOINTERFACE;
1880 }
1881
1882 static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
1883 {
1884     ACImpl *This = impl_from_IAudioClock(iface);
1885     return IAudioClient_AddRef(&This->IAudioClient_iface);
1886 }
1887
1888 static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
1889 {
1890     ACImpl *This = impl_from_IAudioClock(iface);
1891     return IAudioClient_Release(&This->IAudioClient_iface);
1892 }
1893
1894 static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
1895 {
1896     ACImpl *This = impl_from_IAudioClock(iface);
1897
1898     TRACE("(%p)->(%p)\n", This, freq);
1899
1900     *freq = This->fmt->nSamplesPerSec;
1901
1902     return S_OK;
1903 }
1904
1905 static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
1906         UINT64 *qpctime)
1907 {
1908     ACImpl *This = impl_from_IAudioClock(iface);
1909     UINT32 pad;
1910     HRESULT hr;
1911
1912     TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
1913
1914     if(!pos)
1915         return E_POINTER;
1916
1917     EnterCriticalSection(&This->lock);
1918
1919     hr = IAudioClient_GetCurrentPadding(&This->IAudioClient_iface, &pad);
1920     if(FAILED(hr)){
1921         LeaveCriticalSection(&This->lock);
1922         return hr;
1923     }
1924
1925     if(This->dataflow == eRender)
1926         *pos = This->written_frames - pad;
1927     else if(This->dataflow == eCapture)
1928         *pos = This->written_frames + pad;
1929
1930     LeaveCriticalSection(&This->lock);
1931
1932     if(qpctime){
1933         LARGE_INTEGER stamp, freq;
1934         QueryPerformanceCounter(&stamp);
1935         QueryPerformanceFrequency(&freq);
1936         *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
1937     }
1938
1939     return S_OK;
1940 }
1941
1942 static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
1943         DWORD *chars)
1944 {
1945     ACImpl *This = impl_from_IAudioClock(iface);
1946
1947     TRACE("(%p)->(%p)\n", This, chars);
1948
1949     if(!chars)
1950         return E_POINTER;
1951
1952     *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
1953
1954     return S_OK;
1955 }
1956
1957 static const IAudioClockVtbl AudioClock_Vtbl =
1958 {
1959     AudioClock_QueryInterface,
1960     AudioClock_AddRef,
1961     AudioClock_Release,
1962     AudioClock_GetFrequency,
1963     AudioClock_GetPosition,
1964     AudioClock_GetCharacteristics
1965 };
1966
1967 static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
1968         REFIID riid, void **ppv)
1969 {
1970     ACImpl *This = impl_from_IAudioClock2(iface);
1971     return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
1972 }
1973
1974 static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
1975 {
1976     ACImpl *This = impl_from_IAudioClock2(iface);
1977     return IAudioClient_AddRef(&This->IAudioClient_iface);
1978 }
1979
1980 static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
1981 {
1982     ACImpl *This = impl_from_IAudioClock2(iface);
1983     return IAudioClient_Release(&This->IAudioClient_iface);
1984 }
1985
1986 static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
1987         UINT64 *pos, UINT64 *qpctime)
1988 {
1989     ACImpl *This = impl_from_IAudioClock2(iface);
1990
1991     FIXME("(%p)->(%p, %p)\n", This, pos, qpctime);
1992
1993     return E_NOTIMPL;
1994 }
1995
1996 static const IAudioClock2Vtbl AudioClock2_Vtbl =
1997 {
1998     AudioClock2_QueryInterface,
1999     AudioClock2_AddRef,
2000     AudioClock2_Release,
2001     AudioClock2_GetDevicePosition
2002 };
2003
2004 static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
2005 {
2006     AudioSessionWrapper *ret;
2007
2008     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2009             sizeof(AudioSessionWrapper));
2010     if(!ret)
2011         return NULL;
2012
2013     ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
2014     ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
2015     ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
2016
2017     ret->ref = 1;
2018
2019     ret->client = client;
2020     if(client){
2021         ret->session = client->session;
2022         AudioClient_AddRef(&client->IAudioClient_iface);
2023     }
2024
2025     return ret;
2026 }
2027
2028 static HRESULT WINAPI AudioSessionControl_QueryInterface(
2029         IAudioSessionControl2 *iface, REFIID riid, void **ppv)
2030 {
2031     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2032
2033     if(!ppv)
2034         return E_POINTER;
2035     *ppv = NULL;
2036
2037     if(IsEqualIID(riid, &IID_IUnknown) ||
2038             IsEqualIID(riid, &IID_IAudioSessionControl) ||
2039             IsEqualIID(riid, &IID_IAudioSessionControl2))
2040         *ppv = iface;
2041     if(*ppv){
2042         IUnknown_AddRef((IUnknown*)*ppv);
2043         return S_OK;
2044     }
2045
2046     WARN("Unknown interface %s\n", debugstr_guid(riid));
2047     return E_NOINTERFACE;
2048 }
2049
2050 static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
2051 {
2052     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2053     ULONG ref;
2054     ref = InterlockedIncrement(&This->ref);
2055     TRACE("(%p) Refcount now %u\n", This, ref);
2056     return ref;
2057 }
2058
2059 static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
2060 {
2061     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2062     ULONG ref;
2063     ref = InterlockedDecrement(&This->ref);
2064     TRACE("(%p) Refcount now %u\n", This, ref);
2065     if(!ref){
2066         if(This->client){
2067             EnterCriticalSection(&This->client->lock);
2068             This->client->session_wrapper = NULL;
2069             LeaveCriticalSection(&This->client->lock);
2070             AudioClient_Release(&This->client->IAudioClient_iface);
2071         }
2072         HeapFree(GetProcessHeap(), 0, This);
2073     }
2074     return ref;
2075 }
2076
2077 static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
2078         AudioSessionState *state)
2079 {
2080     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2081     ACImpl *client;
2082
2083     TRACE("(%p)->(%p)\n", This, state);
2084
2085     if(!state)
2086         return NULL_PTR_ERR;
2087
2088     EnterCriticalSection(&g_sessions_lock);
2089
2090     if(list_empty(&This->session->clients)){
2091         *state = AudioSessionStateExpired;
2092         LeaveCriticalSection(&g_sessions_lock);
2093         return S_OK;
2094     }
2095
2096     LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
2097         EnterCriticalSection(&client->lock);
2098         if(client->playing){
2099             *state = AudioSessionStateActive;
2100             LeaveCriticalSection(&client->lock);
2101             LeaveCriticalSection(&g_sessions_lock);
2102             return S_OK;
2103         }
2104         LeaveCriticalSection(&client->lock);
2105     }
2106
2107     LeaveCriticalSection(&g_sessions_lock);
2108
2109     *state = AudioSessionStateInactive;
2110
2111     return S_OK;
2112 }
2113
2114 static HRESULT WINAPI AudioSessionControl_GetDisplayName(
2115         IAudioSessionControl2 *iface, WCHAR **name)
2116 {
2117     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2118
2119     FIXME("(%p)->(%p) - stub\n", This, name);
2120
2121     return E_NOTIMPL;
2122 }
2123
2124 static HRESULT WINAPI AudioSessionControl_SetDisplayName(
2125         IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
2126 {
2127     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2128
2129     FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
2130
2131     return E_NOTIMPL;
2132 }
2133
2134 static HRESULT WINAPI AudioSessionControl_GetIconPath(
2135         IAudioSessionControl2 *iface, WCHAR **path)
2136 {
2137     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2138
2139     FIXME("(%p)->(%p) - stub\n", This, path);
2140
2141     return E_NOTIMPL;
2142 }
2143
2144 static HRESULT WINAPI AudioSessionControl_SetIconPath(
2145         IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
2146 {
2147     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2148
2149     FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
2150
2151     return E_NOTIMPL;
2152 }
2153
2154 static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
2155         IAudioSessionControl2 *iface, GUID *group)
2156 {
2157     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2158
2159     FIXME("(%p)->(%p) - stub\n", This, group);
2160
2161     return E_NOTIMPL;
2162 }
2163
2164 static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
2165         IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
2166 {
2167     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2168
2169     FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
2170             debugstr_guid(session));
2171
2172     return E_NOTIMPL;
2173 }
2174
2175 static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
2176         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2177 {
2178     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2179
2180     FIXME("(%p)->(%p) - stub\n", This, events);
2181
2182     return S_OK;
2183 }
2184
2185 static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
2186         IAudioSessionControl2 *iface, IAudioSessionEvents *events)
2187 {
2188     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2189
2190     FIXME("(%p)->(%p) - stub\n", This, events);
2191
2192     return S_OK;
2193 }
2194
2195 static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
2196         IAudioSessionControl2 *iface, WCHAR **id)
2197 {
2198     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2199
2200     FIXME("(%p)->(%p) - stub\n", This, id);
2201
2202     return E_NOTIMPL;
2203 }
2204
2205 static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
2206         IAudioSessionControl2 *iface, WCHAR **id)
2207 {
2208     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2209
2210     FIXME("(%p)->(%p) - stub\n", This, id);
2211
2212     return E_NOTIMPL;
2213 }
2214
2215 static HRESULT WINAPI AudioSessionControl_GetProcessId(
2216         IAudioSessionControl2 *iface, DWORD *pid)
2217 {
2218     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2219
2220     TRACE("(%p)->(%p)\n", This, pid);
2221
2222     if(!pid)
2223         return E_POINTER;
2224
2225     *pid = GetCurrentProcessId();
2226
2227     return S_OK;
2228 }
2229
2230 static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
2231         IAudioSessionControl2 *iface)
2232 {
2233     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2234
2235     TRACE("(%p)\n", This);
2236
2237     return S_FALSE;
2238 }
2239
2240 static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
2241         IAudioSessionControl2 *iface, BOOL optout)
2242 {
2243     AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
2244
2245     TRACE("(%p)->(%d)\n", This, optout);
2246
2247     return S_OK;
2248 }
2249
2250 static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
2251 {
2252     AudioSessionControl_QueryInterface,
2253     AudioSessionControl_AddRef,
2254     AudioSessionControl_Release,
2255     AudioSessionControl_GetState,
2256     AudioSessionControl_GetDisplayName,
2257     AudioSessionControl_SetDisplayName,
2258     AudioSessionControl_GetIconPath,
2259     AudioSessionControl_SetIconPath,
2260     AudioSessionControl_GetGroupingParam,
2261     AudioSessionControl_SetGroupingParam,
2262     AudioSessionControl_RegisterAudioSessionNotification,
2263     AudioSessionControl_UnregisterAudioSessionNotification,
2264     AudioSessionControl_GetSessionIdentifier,
2265     AudioSessionControl_GetSessionInstanceIdentifier,
2266     AudioSessionControl_GetProcessId,
2267     AudioSessionControl_IsSystemSoundsSession,
2268     AudioSessionControl_SetDuckingPreference
2269 };
2270
2271 /* index == -1 means set all channels, otherwise sets only the given channel */
2272 static HRESULT oss_setvol(ACImpl *This, UINT32 index)
2273 {
2274     int setreq, getreq;
2275     unsigned int vol;
2276     unsigned short l;
2277     float level;
2278
2279     if(index == (UINT32)-1){
2280         HRESULT ret = S_OK;
2281         UINT32 i;
2282         for(i = 0; i < This->fmt->nChannels; ++i){
2283             HRESULT hr;
2284             hr = oss_setvol(This, i);
2285             if(FAILED(hr))
2286                 ret = hr;
2287         }
2288         return ret;
2289     }
2290
2291     if(index > 1)
2292         /* OSS doesn't support volume control past the first two channels */
2293         return S_OK;
2294
2295     if(This->dataflow == eRender){
2296         setreq = SNDCTL_DSP_SETPLAYVOL;
2297         getreq = SNDCTL_DSP_GETPLAYVOL;
2298     }else if(This->dataflow == eCapture){
2299         setreq = SNDCTL_DSP_SETRECVOL;
2300         getreq = SNDCTL_DSP_GETRECVOL;
2301     }else
2302         return E_UNEXPECTED;
2303
2304     if(ioctl(This->fd, getreq, &vol) < 0){
2305         if(errno == EINVAL)
2306             /* device doesn't support this call */
2307             return S_OK;
2308
2309         WARN("GET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2310         return E_FAIL;
2311     }
2312
2313     level = This->session->master_vol * This->session->channel_vols[index] *
2314         This->vols[index];
2315     l = level * 100;
2316     if(index == 0)
2317         vol = l | (vol & 0xFF00);
2318     else
2319         vol = (vol & 0xFF) | (l << 8);
2320
2321     if(ioctl(This->fd, setreq, &vol) < 0){
2322         if(errno == EINVAL)
2323             /* device doesn't support this call */
2324             return S_OK;
2325
2326         WARN("SET[REC|PLAY]VOL failed: %d (%s)\n", errno, strerror(errno));
2327         return E_FAIL;
2328     }
2329
2330     return S_OK;
2331 }
2332
2333 static HRESULT oss_session_setvol(AudioSession *session, UINT32 index)
2334 {
2335     HRESULT ret = S_OK;
2336     ACImpl *client;
2337
2338     LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2339         HRESULT hr;
2340         hr = oss_setvol(client, index);
2341         if(FAILED(hr))
2342             ret = hr;
2343     }
2344
2345     return ret;
2346 }
2347
2348 static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
2349         ISimpleAudioVolume *iface, REFIID riid, void **ppv)
2350 {
2351     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2352
2353     if(!ppv)
2354         return E_POINTER;
2355     *ppv = NULL;
2356
2357     if(IsEqualIID(riid, &IID_IUnknown) ||
2358             IsEqualIID(riid, &IID_ISimpleAudioVolume))
2359         *ppv = iface;
2360     if(*ppv){
2361         IUnknown_AddRef((IUnknown*)*ppv);
2362         return S_OK;
2363     }
2364
2365     WARN("Unknown interface %s\n", debugstr_guid(riid));
2366     return E_NOINTERFACE;
2367 }
2368
2369 static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
2370 {
2371     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2372     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2373 }
2374
2375 static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
2376 {
2377     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2378     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2379 }
2380
2381 static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
2382         ISimpleAudioVolume *iface, float level, const GUID *context)
2383 {
2384     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2385     AudioSession *session = This->session;
2386     HRESULT ret;
2387
2388     TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
2389
2390     if(level < 0.f || level > 1.f)
2391         return E_INVALIDARG;
2392
2393     if(context)
2394         FIXME("Notifications not supported yet\n");
2395
2396     EnterCriticalSection(&session->lock);
2397
2398     session->master_vol = level;
2399
2400     ret = oss_session_setvol(session, -1);
2401
2402     LeaveCriticalSection(&session->lock);
2403
2404     return ret;
2405 }
2406
2407 static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
2408         ISimpleAudioVolume *iface, float *level)
2409 {
2410     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2411     AudioSession *session = This->session;
2412
2413     TRACE("(%p)->(%p)\n", session, level);
2414
2415     if(!level)
2416         return NULL_PTR_ERR;
2417
2418     *level = session->master_vol;
2419
2420     return S_OK;
2421 }
2422
2423 static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
2424         BOOL mute, const GUID *context)
2425 {
2426     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2427     AudioSession *session = This->session;
2428
2429     TRACE("(%p)->(%u, %p)\n", session, mute, context);
2430
2431     EnterCriticalSection(&session->lock);
2432
2433     if(!mute && session->mute){
2434         ACImpl *client;
2435
2436         session->mute = mute;
2437
2438         LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry){
2439             EnterCriticalSection(&client->lock);
2440             if(ioctl(client->fd, SNDCTL_DSP_SKIP) < 0)
2441                 WARN("Error calling DSP_SKIP: %d (%s)\n", errno,
2442                         strerror(errno));
2443             oss_write_data(client);
2444             LeaveCriticalSection(&client->lock);
2445         }
2446     }else
2447         session->mute = mute;
2448
2449     LeaveCriticalSection(&session->lock);
2450
2451     return S_OK;
2452 }
2453
2454 static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
2455         BOOL *mute)
2456 {
2457     AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
2458     AudioSession *session = This->session;
2459
2460     TRACE("(%p)->(%p)\n", session, mute);
2461
2462     if(!mute)
2463         return NULL_PTR_ERR;
2464
2465     *mute = This->session->mute;
2466
2467     return S_OK;
2468 }
2469
2470 static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl  =
2471 {
2472     SimpleAudioVolume_QueryInterface,
2473     SimpleAudioVolume_AddRef,
2474     SimpleAudioVolume_Release,
2475     SimpleAudioVolume_SetMasterVolume,
2476     SimpleAudioVolume_GetMasterVolume,
2477     SimpleAudioVolume_SetMute,
2478     SimpleAudioVolume_GetMute
2479 };
2480
2481 static HRESULT WINAPI AudioStreamVolume_QueryInterface(
2482         IAudioStreamVolume *iface, REFIID riid, void **ppv)
2483 {
2484     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2485
2486     if(!ppv)
2487         return E_POINTER;
2488     *ppv = NULL;
2489
2490     if(IsEqualIID(riid, &IID_IUnknown) ||
2491             IsEqualIID(riid, &IID_IAudioStreamVolume))
2492         *ppv = iface;
2493     if(*ppv){
2494         IUnknown_AddRef((IUnknown*)*ppv);
2495         return S_OK;
2496     }
2497
2498     WARN("Unknown interface %s\n", debugstr_guid(riid));
2499     return E_NOINTERFACE;
2500 }
2501
2502 static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
2503 {
2504     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2505     return IAudioClient_AddRef(&This->IAudioClient_iface);
2506 }
2507
2508 static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
2509 {
2510     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2511     return IAudioClient_Release(&This->IAudioClient_iface);
2512 }
2513
2514 static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
2515         IAudioStreamVolume *iface, UINT32 *out)
2516 {
2517     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2518
2519     TRACE("(%p)->(%p)\n", This, out);
2520
2521     if(!out)
2522         return E_POINTER;
2523
2524     *out = This->fmt->nChannels;
2525
2526     return S_OK;
2527 }
2528
2529 static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
2530         IAudioStreamVolume *iface, UINT32 index, float level)
2531 {
2532     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2533     HRESULT ret;
2534
2535     TRACE("(%p)->(%d, %f)\n", This, index, level);
2536
2537     if(level < 0.f || level > 1.f)
2538         return E_INVALIDARG;
2539
2540     if(index >= This->fmt->nChannels)
2541         return E_INVALIDARG;
2542
2543     EnterCriticalSection(&This->lock);
2544
2545     This->vols[index] = level;
2546
2547     ret = oss_setvol(This, index);
2548
2549     LeaveCriticalSection(&This->lock);
2550
2551     return ret;
2552 }
2553
2554 static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
2555         IAudioStreamVolume *iface, UINT32 index, float *level)
2556 {
2557     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2558
2559     TRACE("(%p)->(%d, %p)\n", This, index, level);
2560
2561     if(!level)
2562         return E_POINTER;
2563
2564     if(index >= This->fmt->nChannels)
2565         return E_INVALIDARG;
2566
2567     *level = This->vols[index];
2568
2569     return S_OK;
2570 }
2571
2572 static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
2573         IAudioStreamVolume *iface, UINT32 count, const float *levels)
2574 {
2575     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2576     int i;
2577     HRESULT ret;
2578
2579     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2580
2581     if(!levels)
2582         return E_POINTER;
2583
2584     if(count != This->fmt->nChannels)
2585         return E_INVALIDARG;
2586
2587     EnterCriticalSection(&This->lock);
2588
2589     for(i = 0; i < count; ++i)
2590         This->vols[i] = levels[i];
2591
2592     ret = oss_setvol(This, -1);
2593
2594     LeaveCriticalSection(&This->lock);
2595
2596     return ret;
2597 }
2598
2599 static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
2600         IAudioStreamVolume *iface, UINT32 count, float *levels)
2601 {
2602     ACImpl *This = impl_from_IAudioStreamVolume(iface);
2603     int i;
2604
2605     TRACE("(%p)->(%d, %p)\n", This, count, levels);
2606
2607     if(!levels)
2608         return E_POINTER;
2609
2610     if(count != This->fmt->nChannels)
2611         return E_INVALIDARG;
2612
2613     EnterCriticalSection(&This->lock);
2614
2615     for(i = 0; i < count; ++i)
2616         levels[i] = This->vols[i];
2617
2618     LeaveCriticalSection(&This->lock);
2619
2620     return S_OK;
2621 }
2622
2623 static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
2624 {
2625     AudioStreamVolume_QueryInterface,
2626     AudioStreamVolume_AddRef,
2627     AudioStreamVolume_Release,
2628     AudioStreamVolume_GetChannelCount,
2629     AudioStreamVolume_SetChannelVolume,
2630     AudioStreamVolume_GetChannelVolume,
2631     AudioStreamVolume_SetAllVolumes,
2632     AudioStreamVolume_GetAllVolumes
2633 };
2634
2635 static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
2636         IChannelAudioVolume *iface, REFIID riid, void **ppv)
2637 {
2638     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2639
2640     if(!ppv)
2641         return E_POINTER;
2642     *ppv = NULL;
2643
2644     if(IsEqualIID(riid, &IID_IUnknown) ||
2645             IsEqualIID(riid, &IID_IChannelAudioVolume))
2646         *ppv = iface;
2647     if(*ppv){
2648         IUnknown_AddRef((IUnknown*)*ppv);
2649         return S_OK;
2650     }
2651
2652     WARN("Unknown interface %s\n", debugstr_guid(riid));
2653     return E_NOINTERFACE;
2654 }
2655
2656 static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
2657 {
2658     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2659     return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
2660 }
2661
2662 static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
2663 {
2664     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2665     return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
2666 }
2667
2668 static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
2669         IChannelAudioVolume *iface, UINT32 *out)
2670 {
2671     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2672     AudioSession *session = This->session;
2673
2674     TRACE("(%p)->(%p)\n", session, out);
2675
2676     if(!out)
2677         return NULL_PTR_ERR;
2678
2679     *out = session->channel_count;
2680
2681     return S_OK;
2682 }
2683
2684 static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
2685         IChannelAudioVolume *iface, UINT32 index, float level,
2686         const GUID *context)
2687 {
2688     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2689     AudioSession *session = This->session;
2690     HRESULT ret;
2691
2692     TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
2693             wine_dbgstr_guid(context));
2694
2695     if(level < 0.f || level > 1.f)
2696         return E_INVALIDARG;
2697
2698     if(index >= session->channel_count)
2699         return E_INVALIDARG;
2700
2701     if(context)
2702         FIXME("Notifications not supported yet\n");
2703
2704     EnterCriticalSection(&session->lock);
2705
2706     session->channel_vols[index] = level;
2707
2708     ret = oss_session_setvol(session, index);
2709
2710     LeaveCriticalSection(&session->lock);
2711
2712     return ret;
2713 }
2714
2715 static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
2716         IChannelAudioVolume *iface, UINT32 index, float *level)
2717 {
2718     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2719     AudioSession *session = This->session;
2720
2721     TRACE("(%p)->(%d, %p)\n", session, index, level);
2722
2723     if(!level)
2724         return NULL_PTR_ERR;
2725
2726     if(index >= session->channel_count)
2727         return E_INVALIDARG;
2728
2729     *level = session->channel_vols[index];
2730
2731     return S_OK;
2732 }
2733
2734 static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
2735         IChannelAudioVolume *iface, UINT32 count, const float *levels,
2736         const GUID *context)
2737 {
2738     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2739     AudioSession *session = This->session;
2740     int i;
2741     HRESULT ret;
2742
2743     TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
2744             wine_dbgstr_guid(context));
2745
2746     if(!levels)
2747         return NULL_PTR_ERR;
2748
2749     if(count != session->channel_count)
2750         return E_INVALIDARG;
2751
2752     if(context)
2753         FIXME("Notifications not supported yet\n");
2754
2755     EnterCriticalSection(&session->lock);
2756
2757     for(i = 0; i < count; ++i)
2758         session->channel_vols[i] = levels[i];
2759
2760     ret = oss_session_setvol(session, -1);
2761
2762     LeaveCriticalSection(&session->lock);
2763
2764     return ret;
2765 }
2766
2767 static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
2768         IChannelAudioVolume *iface, UINT32 count, float *levels)
2769 {
2770     AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
2771     AudioSession *session = This->session;
2772     int i;
2773
2774     TRACE("(%p)->(%d, %p)\n", session, count, levels);
2775
2776     if(!levels)
2777         return NULL_PTR_ERR;
2778
2779     if(count != session->channel_count)
2780         return E_INVALIDARG;
2781
2782     for(i = 0; i < count; ++i)
2783         levels[i] = session->channel_vols[i];
2784
2785     return S_OK;
2786 }
2787
2788 static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
2789 {
2790     ChannelAudioVolume_QueryInterface,
2791     ChannelAudioVolume_AddRef,
2792     ChannelAudioVolume_Release,
2793     ChannelAudioVolume_GetChannelCount,
2794     ChannelAudioVolume_SetChannelVolume,
2795     ChannelAudioVolume_GetChannelVolume,
2796     ChannelAudioVolume_SetAllVolumes,
2797     ChannelAudioVolume_GetAllVolumes
2798 };
2799
2800 static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
2801         REFIID riid, void **ppv)
2802 {
2803     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
2804
2805     if(!ppv)
2806         return E_POINTER;
2807     *ppv = NULL;
2808
2809     if(IsEqualIID(riid, &IID_IUnknown) ||
2810             IsEqualIID(riid, &IID_IAudioSessionManager) ||
2811             IsEqualIID(riid, &IID_IAudioSessionManager2))
2812         *ppv = iface;
2813     if(*ppv){
2814         IUnknown_AddRef((IUnknown*)*ppv);
2815         return S_OK;
2816     }
2817
2818     WARN("Unknown interface %s\n", debugstr_guid(riid));
2819     return E_NOINTERFACE;
2820 }
2821
2822 static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
2823 {
2824     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2825     ULONG ref;
2826     ref = InterlockedIncrement(&This->ref);
2827     TRACE("(%p) Refcount now %u\n", This, ref);
2828     return ref;
2829 }
2830
2831 static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
2832 {
2833     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2834     ULONG ref;
2835     ref = InterlockedDecrement(&This->ref);
2836     TRACE("(%p) Refcount now %u\n", This, ref);
2837     if(!ref)
2838         HeapFree(GetProcessHeap(), 0, This);
2839     return ref;
2840 }
2841
2842 static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
2843         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2844         IAudioSessionControl **out)
2845 {
2846     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2847     AudioSession *session;
2848     AudioSessionWrapper *wrapper;
2849     HRESULT hr;
2850
2851     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2852             flags, out);
2853
2854     hr = get_audio_session(session_guid, This->device, 0, &session);
2855     if(FAILED(hr))
2856         return hr;
2857
2858     wrapper = AudioSessionWrapper_Create(NULL);
2859     if(!wrapper)
2860         return E_OUTOFMEMORY;
2861
2862     wrapper->session = session;
2863
2864     *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
2865
2866     return S_OK;
2867 }
2868
2869 static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
2870         IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
2871         ISimpleAudioVolume **out)
2872 {
2873     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2874     AudioSession *session;
2875     AudioSessionWrapper *wrapper;
2876     HRESULT hr;
2877
2878     TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
2879             flags, out);
2880
2881     hr = get_audio_session(session_guid, This->device, 0, &session);
2882     if(FAILED(hr))
2883         return hr;
2884
2885     wrapper = AudioSessionWrapper_Create(NULL);
2886     if(!wrapper)
2887         return E_OUTOFMEMORY;
2888
2889     wrapper->session = session;
2890
2891     *out = &wrapper->ISimpleAudioVolume_iface;
2892
2893     return S_OK;
2894 }
2895
2896 static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
2897         IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
2898 {
2899     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2900     FIXME("(%p)->(%p) - stub\n", This, out);
2901     return E_NOTIMPL;
2902 }
2903
2904 static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
2905         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2906 {
2907     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2908     FIXME("(%p)->(%p) - stub\n", This, notification);
2909     return E_NOTIMPL;
2910 }
2911
2912 static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
2913         IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
2914 {
2915     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2916     FIXME("(%p)->(%p) - stub\n", This, notification);
2917     return E_NOTIMPL;
2918 }
2919
2920 static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
2921         IAudioSessionManager2 *iface, const WCHAR *session_id,
2922         IAudioVolumeDuckNotification *notification)
2923 {
2924     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2925     FIXME("(%p)->(%p) - stub\n", This, notification);
2926     return E_NOTIMPL;
2927 }
2928
2929 static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
2930         IAudioSessionManager2 *iface,
2931         IAudioVolumeDuckNotification *notification)
2932 {
2933     SessionMgr *This = impl_from_IAudioSessionManager2(iface);
2934     FIXME("(%p)->(%p) - stub\n", This, notification);
2935     return E_NOTIMPL;
2936 }
2937
2938 static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
2939 {
2940     AudioSessionManager_QueryInterface,
2941     AudioSessionManager_AddRef,
2942     AudioSessionManager_Release,
2943     AudioSessionManager_GetAudioSessionControl,
2944     AudioSessionManager_GetSimpleAudioVolume,
2945     AudioSessionManager_GetSessionEnumerator,
2946     AudioSessionManager_RegisterSessionNotification,
2947     AudioSessionManager_UnregisterSessionNotification,
2948     AudioSessionManager_RegisterDuckNotification,
2949     AudioSessionManager_UnregisterDuckNotification
2950 };
2951
2952 HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
2953         IAudioSessionManager2 **out)
2954 {
2955     SessionMgr *This;
2956
2957     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
2958     if(!This)
2959         return E_OUTOFMEMORY;
2960
2961     This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
2962     This->device = device;
2963     This->ref = 1;
2964
2965     *out = &This->IAudioSessionManager2_iface;
2966
2967     return S_OK;
2968 }