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