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