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