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