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