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