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